Split Údaje třída přístup do čtečky a spisovatel nebo zkombinovat?




To by mohlo být na „discussy“ straně, ale já bych opravdu rád slyšel váš názor na toto téma.


Dříve jsem často psán pro přístup k datům třídy, které ovládal i čtení a psaní, což často vedlo ke špatné pojmenování, jako FooIoHandler atd pravidlo, že třídy, které jsou těžko jméno pravděpodobně špatně navrženy nasvědčuje tomu, že to není dobré řešení.


Tak jsem nedávno začala rozdělovat přístup k datům do FooWriter a FooReader, což vede k hezčí jmen a poskytuje některé další flexibilitu, ale zároveň jsem se trochu jako udržet pohromadě, v případě, že třídy nejsou velké.


Je separační čtecí / zapisovací lepší design, nebo bych měl zkombinovat? Kdybych je měl spojit, co to sakra mám název třídy?


Díky / Erik
ORM může být váš nejlepší řešení.   

Nebo použít typ úložiště vzor, s „thingContext“ objekt, který je zodpovědný za státní vytrvalost.


Osobně používám Active Record, kde ušetřit logiku se peče do základní třídy, ale já odjíždím to ve prospěch NHibernate stylu úložiště vzor. Příspěvek na DDD a testování věci bez db je velmi příjemné mít v rámcové typu situace, kdy je moje obchodní logiky nyní získává trakci na novém uživatelském rozhraní.
<p>jako uživatel 100% foss bych rád řekl ano:</p><p>funguje to však dobře, dokud si neuvědomíte, že knihovna je implementována napůl a je nová a skvělá a byla by opravdu užitečná (jako příklad linq to sql)</p> <p>psaní plynulého rozhraní (s ním jsem <a href="http://www.google.ca/url?sa=t&amp;source=web&amp;cd=1&amp;ved=0cbuqfjaa&amp;url=http%3a%2f%2fsoapboxautomation.com%2fproducts%2ffluentdwelling%2f&amp;ei=ao6ttcuck8sdgqesvpsqda&amp;usg=afqjcngcf99lzbzlrfvnrtst7qsww3kxwg">dabbled</a> ) vyžaduje více úsilí, ale má to výplaty, protože pokud to uděláte správně, je výsledný uživatelský kód jasnější. je to v zásadě forma specifického jazykového jazyka.</p><p>jinými slovy, pokud je váš kód načten mnohem více, než je napsán (a jaký kód není?), měli byste zvážit vytvoření plynulého rozhraní.</p><p>plynulá rozhraní jsou více o kontextu a jsou mnohem víc než jen způsoby konfigurace objektů. jak vidíte ve výše uvedeném odkazu, k dosažení:</p><ol> <li>kontext (takže když obvykle provádíte mnoho akcí ve stejném pořadí, můžete je zřetězit, aniž byste museli znovu a znovu prohlašovat svůj kontext).</li> <li>viditelnost (když jdete na <code>objecta.</code> pak vám inteligence dává spoustu rad. v mém případě výše, <code>plm.led.</code> vám poskytuje všechny možnosti pro ovládání vestavěné led a <code>plm.network.</code> vám poskytuje věci, které můžete dělat se síťovým rozhraním. <code>plm.network.x10.</code> vám dává podmnožinu síťových akcí pro zařízení x10. u inicializátorů konstruktoru to nedostanete (pokud si nepřejete, aby byl objekt konstruován pro každý jiný typ akce, který není idiomatický).</li> <li>reflexe (nepoužívá se ve výše uvedeném příkladu) - schopnost převzít výraz linq a manipulovat s ním je velmi výkonný nástroj, zejména v některých pomocných api, které jsem vytvořil pro testy jednotek. dokážu předat výraz getter get, sestavit spoustu užitečných výrazů, zkompilovat a spustit je, nebo dokonce použít getter k nastavení mého kontextu.</li> </ol><p>jedna věc, kterou obvykle dělám, je:</p><pre><code>test.property(t =&gt; t.someproperty) .initializedto(string.empty) .cantbenull() // tries to set to null and asserts argumentnullexception .yaddayadda(); </code></pre><p>nechápu, jak můžete něco takového udělat i bez plynulého rozhraní.</p><p><strong> edit 2 </strong>: můžete také udělat opravdu zajímavá vylepšení čitelnosti, jako například:</p><pre><code>test.listproperty(t =&gt; t.mylist) .shouldhave(18).items() .andthenafter(t =&gt; testaddingitemtolist(t)) .shouldhave(19).items(); </code></pre> Nejsem si jistá, jestli vám v tomhle bude někdo schopný dobře poradit, protože úrovně jednotlivých lekcí jsou úplně nová funkce. Teprv nedávno se začaly testovat a většina lidí je ještě nemá. (Myslím, že je zatím nabízejí jen nově zaregistrovaným účtům.)


Mně by přišlo nejrozumnější to nějak nakombinovat, nejdřív probrat nějaké množství lekcí na nižší úrovni a pak postupně přitvrdit. Ale každému to může vyhovovat nějak jinak.


Zkuste a kdyžtak dejte vědět, jaké s tím budete mít zkušenosti. Videl bych to na prava na slozce. Pouzivam osobne XP, ale na nich se musi v moznostech slozky odzaskrtnout pole pouzivat zjednodusene sdileni. Po te pri kazdem nastavovani sdileni slozky pribude zalozka s pravama, kde se da nastavit uzivatel nebo skupina, ktera do slozky muze vstupovat, zapisovat atd. Některé zvukovky umí sloučit nebo rozdělit svůj přední a zadní výstup, ale různé zvukovky sloučit nejde. Možná by šel napsat program co pošle totéž na víc zvukovek, ale obávám se že reprodukce nemusí být synchronní.Jediné co funguje, je v programech které to umí vybrat jiné výstupní zařízení než je výchozí. Pak půjde zvuk z různých výstupů. <p>příkaz <code>merge</code> má složitou syntaxi a ještě složitější implementaci, ale v zásadě jde o spojení dvou tabulek, filtrování dolů na řádky, které je třeba změnit (vložit, aktualizovat nebo smazat), a poté provést požadované změny. vzhledem k těmto vzorovým údajům:</p><pre><code>declare @categoryitem as table ( categoryid integer not null, itemid integer not null, primary key (categoryid, itemid), unique (itemid, categoryid) ); declare @datasource as table ( categoryid integer not null, itemid integer not null primary key (categoryid, itemid) ); insert @categoryitem (categoryid, itemid) values (1, 1), (1, 2), (1, 3), (2, 1), (2, 3), (3, 5), (3, 6), (4, 5); insert @datasource (categoryid, itemid) values (2, 2); </code></pre><p><strong> cíl </strong></p><pre><code>╔════════════╦════════╗ ║ categoryid ║ itemid ║ ╠════════════╬════════╣ ║ 1 ║ 1 ║ ║ 2 ║ 1 ║ ║ 1 ║ 2 ║ ║ 1 ║ 3 ║ ║ 2 ║ 3 ║ ║ 3 ║ 5 ║ ║ 4 ║ 5 ║ ║ 3 ║ 6 ║ ╚════════════╩════════╝ </code></pre><p><strong> zdroj </strong></p><pre><code>╔════════════╦════════╗ ║ categoryid ║ itemid ║ ╠════════════╬════════╣ ║ 2 ║ 2 ║ ╚════════════╩════════╝ </code></pre><p>požadovaným výsledkem je nahrazení dat v cíli daty ze zdroje, ale pouze pro <code>categoryid = 2</code>. po výše uvedeném popisu <code>merge</code> bychom měli napsat dotaz, který spojuje zdroj a cíl pouze na klíče, a filtrovat řádky pouze v klauzulích <code>when</code>:</p><pre><code>merge into @categoryitem as target using @datasource as source on source.itemid = target.itemid and source.categoryid = target.categoryid when not matched by source and target.categoryid = 2 then delete when not matched by target and source.categoryid = 2 then insert (categoryid, itemid) values (categoryid, itemid) output $action, isnull(inserted.categoryid, deleted.categoryid) as categoryid, isnull(inserted.itemid, deleted.itemid) as itemid ; </code></pre><p>to dává následující výsledky:</p><pre><code>╔═════════╦════════════╦════════╗ ║ $action ║ categoryid ║ itemid ║ ╠═════════╬════════════╬════════╣ ║ delete ║ 2 ║ 1 ║ ║ insert ║ 2 ║ 2 ║ ║ delete ║ 2 ║ 3 ║ ╚═════════╩════════════╩════════╝ ╔════════════╦════════╗ ║ categoryid ║ itemid ║ ╠════════════╬════════╣ ║ 1 ║ 1 ║ ║ 1 ║ 2 ║ ║ 1 ║ 3 ║ ║ 2 ║ 2 ║ ║ 3 ║ 5 ║ ║ 3 ║ 6 ║ ║ 4 ║ 5 ║ ╚════════════╩════════╝ </code></pre><p>realizační plán je: <img src="https://i.stack.imgur.com/fovhu.jpg" alt="merge plan"></p><p>všimněte si, že jsou obě tabulky plně naskenovány. můžeme to považovat za neefektivní, protože pouze řádky, kde <code>categoryid = 2</code> bude ovlivněno v cílové tabulce. zde přicházejí varování v books online. jeden chybný pokus o optimalizaci, aby se dotkl pouze nezbytných řádků v cíli, je:</p><pre><code>merge into @categoryitem as target using ( select categoryid, itemid from @datasource as ds where categoryid = 2 ) as source on source.itemid = target.itemid and target.categoryid = 2 when not matched by target then insert (categoryid, itemid) values (categoryid, itemid) when not matched by source then delete output $action, isnull(inserted.categoryid, deleted.categoryid) as categoryid, isnull(inserted.itemid, deleted.itemid) as itemid ; </code></pre><p>logika v klauzuli <code>on</code> je použita jako součást spojení. v tomto případě je spojení úplným vnějším spojením (viz <a href="http://technet.microsoft.com/en-us/library/bb522522%28v=sql.105%29.aspx">tento záznam books online</a> proč). použití kontroly kategorie 2 na cílových řádcích jako součásti vnějšího spojení nakonec povede k odstranění řádků s jinou hodnotou (protože neodpovídají zdroji):</p><pre><code>╔═════════╦════════════╦════════╗ ║ $action ║ categoryid ║ itemid ║ ╠═════════╬════════════╬════════╣ ║ delete ║ 1 ║ 1 ║ ║ delete ║ 1 ║ 2 ║ ║ delete ║ 1 ║ 3 ║ ║ delete ║ 2 ║ 1 ║ ║ insert ║ 2 ║ 2 ║ ║ delete ║ 2 ║ 3 ║ ║ delete ║ 3 ║ 5 ║ ║ delete ║ 3 ║ 6 ║ ║ delete ║ 4 ║ 5 ║ ╚═════════╩════════════╩════════╝ ╔════════════╦════════╗ ║ categoryid ║ itemid ║ ╠════════════╬════════╣ ║ 2 ║ 2 ║ ╚════════════╩════════╝ </code></pre><p>kořenová příčina je ze stejného důvodu, proč se predikáty chovají v klauzuli vnější spojení <code>on</code> odlišně, než když jsou specifikovány v klauzuli <code>where</code>. syntaxe <code>merge</code> (a implementace spojení v závislosti na zadaných klauzulích) jen ztěžují vidět, že tomu tak je.</p><p> <a href="http://technet.microsoft.com/en-us/library/bb510625%28v=sql.105%29.aspx">navádění v books online</a> (rozšířeno v položce <a href="http://technet.microsoft.com/en-us/library/cc879317%28v=sql.105%29.aspx">optimizing performance</a> ) nabízí navádění, které zajistí, že správná sémantika je vyjádřena pomocí syntaxe <code>merge</code>, aniž by uživatel nutně musel muset pochopit všechny podrobnosti implementace nebo zohlednit způsoby, kterými by optimalizátor mohl legitimně přeskupit věci z důvodů efektivnosti provádění.</p><p>dokumentace nabízí tři možné způsoby implementace časného filtrování:</p><p><strong> zadání podmínky filtrování v klauzuli <code>when</code> </strong> zaručuje správné výsledky, ale může znamenat, že více řádků je čteno a zpracováno ze zdroje a cíle tabulky, než je nezbytně nutné (viz první příklad).</p><p><strong> aktualizace prostřednictvím zobrazení </strong>, která obsahuje podmínku filtrování, také zaručuje správné výsledky (protože změněné řádky musí být přístupné pro aktualizaci prostřednictvím zobrazení), ale vyžaduje to vyhrazené zobrazení, které splňuje liché podmínky pro aktualizaci zobrazení.</p><p><strong> použití společného výrazu tabulky </strong> přináší podobné riziko při přidávání predikátů k klauzuli <code>on</code>, ale z poněkud odlišných důvodů. v mnoha případech to bude bezpečné, ale vyžaduje to odbornou analýzu prováděcího plánu, aby se to potvrdilo (a rozsáhlé praktické testování). například:</p><pre><code>with target as ( select * from @categoryitem where categoryid = 2 ) merge into target using ( select categoryid, itemid from @datasource where categoryid = 2 ) as source on source.itemid = target.itemid and source.categoryid = target.categoryid when not matched by target then insert (categoryid, itemid) values (categoryid, itemid) when not matched by source then delete output $action, isnull(inserted.categoryid, deleted.categoryid) as categoryid, isnull(inserted.itemid, deleted.itemid) as itemid ; </code></pre><p>výsledkem jsou správné výsledky (neopakované) s optimálnějším plánem:</p><p><img src="https://i.stack.imgur.com/tazmk.jpg" alt="merge plan 2"></p><p>plán čte pouze řádky pro kategorii 2 z cílové tabulky. to může být důležitým hlediskem výkonu, pokud je cílová tabulka velká, ale je příliš snadné tuto chybu získat pomocí syntaxe <code>merge</code>.</p><p>někdy je snazší zapsat <code>merge</code> jako samostatné operace dml. tento přístup může dokonce <strong> vést lépe </strong> než jediný <code>merge</code>, což je skutečnost, která lidi často překvapuje.</p><pre><code>delete ci from @categoryitem as ci where ci.categoryid = 2 and not exists ( select 1 from @datasource as ds where ds.itemid = ci.itemid and ds.categoryid = ci.categoryid ); insert @categoryitem select ds.categoryid, ds.itemid from @datasource as ds where ds.categoryid = 2; </code></pre> Možná si myslíš, že jsi "skvělej", ale nebylo by na čase to odnést do servisu?!Na krabici, kde bylo CPU a chladič je značení nad čárovým kódem: YD1600BBAFBOX ("af" jsou snad jasné), na tepelném rozvaděči CPU je také typové značení.Pokud tohle nejsi schopen najít, tak servis je nejlepší řešení. Přídavné slovo: "nový" má také jiný význam, než mu přikládáš. To je pak těžká "domluva", když význam slov je na obou komunikačních stranách vykládán zcela jinak. <p><strong> souhrn </strong></p><ol> <li>pokud máte problémy se zamykáním, máte problém s kódem: nejedná se o databázový stroj</li> <li>není to kouzelná střela</li> <li>můžete přidat další problémy</li> </ol><p><strong> zatížení </strong></p><p>také zvýší zatížení vašeho tempdb a <a href="https://web.archive.org/web/20170130011816/http://sqlblog.com/blogs/alexander\_kuznetsov/archive/2008/07/12/cpu-overhead-for-higher-isolation-levels.aspx"> cpu </a> . viz také:</p><ul> <li> <a href="https://web.archive.org/web/20170915173116/http://sqlblog.com/blogs/linchi\_shea/archive/2007/10/05/performance-impact-the-potential-cost-of-read-committed-snapshot.aspx">"dopad na výkon: potenciální náklady na čtení\_kompletní\_snapshot"</a> (linchi shea)</li> </ul><p><strong> bezpečnost </strong></p><p>nejdůležitější je, že izolace snímků <em> není v mnoha případech bezpečná </em> <em> ve výchozím nastavení </em>. přečtěte si <a href="https://en.wikipedia.org/wiki/snapshot\_isolation#definition">"snapshot izolace" (wikipedia)</a> pro další informace o anomáliích se skreslením. další část je „jak provést sériovou izolaci snímkování“.</p><blockquote> <p>obecně tedy izolace snímků přináší některé problémy s udržováním netriviálních omezení na uživatele, který nemusí ocenit potenciální úskalí ani možná řešení. nevýhodou tohoto převodu je lepší výkon.</p> </blockquote><p>viz také:</p><ul> <li> <a href="http://www.jimmcleod.net/blog/index.php/2009/08/27/the-potential-dangers-of-the-read-committed-snapshot-isolation-level">"potenciální nebezpečí čtecí úrovně izolace snímaného odevzdání"</a> (jimmcleod, sporný v komentářích alexa kuznetsova)</li> <li> <a href="http://nickberardi.com/deadlocked-read-committed-snapshot-explained/">deadlocked !: "číst potvrzující snímek" vysvětlil</a> (nick berardi)</li> <li> <a href="https://blogs.msdn.microsoft.com/craigfr/2007/05/16/serializable-vs-snapshot-isolation-level/">serializable vs. snapshot isolation level, marble problem</a> (craig freedman)</li> <li> <a href="https://web.archive.org/web/20170511045506/http://sqlblog.com/blogs/alexander\_kuznetsov/archive/2011/08/02/reads-involving-udfs-under-read-committed-snapshot-may-seem-inconsistent.aspx">čtení zahrnující udf v read\_committed\_snapshot se může zdát nekonzistentní</a> (alex kuznetsov)</li> </ul> <p>už nemůžu najít ten pravý příspěvek, ale eric lippert (a možná i několik dalších softies) se při několika příležitostech opíral o to, jak je linq <strong>deklarativní</strong>, což je pro několik tříd problémů mnohem intuitivnější než <strong>imperativní</strong> syntaxe.</p><p>linq umožňuje psát kód, který vyjadřuje <em> záměr </em>, nikoli mechanismus <em> </em> .</p><p>řekni mi, co je lépe čitelné. tento:</p><pre class="lang-cs prettyprint-override"><code>ienumerable&lt;customer&gt; getvipcustomers(ienumerable&lt;customer&gt; source) { list&lt;customer&gt; results = new list&lt;customer&gt;(); foreach (customer c in source) { if (c.firstname == "aaron") { results.add(c); } } results.sort(new lastnamecomparer()); return results; } class lastnamecomparer : icomparer&lt;customer&gt; { public int compare(customer a, customer b) { return x.lastname.compareto(b.lastname); } } </code></pre><p>nebo toto?</p><pre class="lang-cs prettyprint-override"><code>ienumerable&lt;customer&gt; getvipcustomers(ienumerable&lt;customer&gt; source) { return from c in source where c.firstname == "aaron" orderby c.lastname select c; } </code></pre><p>nebo dokonce tohle?</p><pre class="lang-cs prettyprint-override"><code>ienumerable&lt;customer&gt; getvipcustomers(ienumerable&lt;customer&gt; source) { return source.where(c =&gt; c.firstname == "aaron").orderby(c =&gt; c.lastname); } </code></pre><p>prvním příkladem je jen svazek zbytečných kotlových desek, aby bylo dosaženo co nejjednodušších výsledků. každý, kdo si myslí, že je <em> více </em> čitelnější než verze linq, musí nechat vyšetřit hlavu. nejen to, ale první ztrácí paměť. nemůžete to ani napsat pomocí <code>yield return</code> kvůli třídění.</p><p>váš spolupracovník může říct, co chce; osobně si myslím, že linq nezměřitelně zlepšil <em> můj </em> kód čitelnosti.</p><p>ani o linqovi není nic „relačního“. může mít některé povrchové podobnosti s sql, ale nepokouší se v jakémkoli tvaru nebo formě implementovat relační počet. je to jen banda rozšíření, která usnadňují vyhledávání a projektování sekvencí. „dotaz“ neznamená „relační“ a ve skutečnosti existuje několik nerelačních databází, které používají syntaxi podobnou sql. linq je <em> čistě </em> objektově orientovaný, prostě se stává, že pracuje s relačními databázemi prostřednictvím frameworků jako linq do sql kvůli nějakému výrazu voodoo stromů a chytrému designu od tým c #, čímž se anonymní funkce implicitně převádějí na stromy výrazů.</p> <p>je v pořádku, aby vnořené poddotazy používaly stejné aliasy, jaké byly použity v nadřazeném dotazu, i když to může být pro někoho, kdo čte kód, matoucí. jmenný prostor pro aliasy vnořeného poddotazu je oddělený od jmenného prostoru nadřazeného. například dotaz níže obsahuje vnořený poddotaz <code>b</code>, který také obsahuje alias <code>b</code>. to by bylo potenciálně matoucí pro programátora, ale v pořádku s motorem dbms:</p><pre><code> select a.foo ,b.bar ,b.barcount from (select b.bar ,count (*) as barcount from bartable b join othertable o on b.othertableid = o.othertableid group by b.bar) b join foobar a on a.bar = b.bar </code></pre><p>na korelovaném poddotazu máte přístup k aliasu nadřazeného prvku, takže aliasy musí být jedinečné v nadřazeném dotazu a korelovaném poddotazu. vezmeme-li korelovaný poddotaz, jako je pod, máme jediný, globální jmenný prostor sdílený mezi nadřazeným dotazem a korelovaným poddotazem:</p><pre><code>select a.foo ,b.bar from foobar a join bar b on b.foobarid = a.foobarid where not exists (select 1 from bar b2 where b2.barcategoryid = b.barcategoryid and b2.bardate &gt; b.bardate) </code></pre><p>korelovaný dílčí dotaz nemá alias, protože se neúčastní spojení jako takového<sup>1</sup>. odkazy <code>b</code> a <code>b2</code> pro <code>bar</code> jsou oba k dispozici pro poddotaz, protože korelované poddotazy sdílejí svůj jmenný prostor pro aliasy s nadřazeným.</p><hr><p><sup>1</sup> všimněte si, že optimalizátor se může rozhodnout použít operátory spojení v rámci plánu v zákulisí, i když skutečnou zadanou operací je korelovaný poddotaz a nikoli spojení proti vnořenému poddotazu.</p>