İş mantığında veritabanı değerlerine referans verme


43

Sanırım bu zor kodlama ve en iyi uygulamalar hakkında başka bir soru. Diyelim ki bir değerler listesine sahibim, veritabanında depolanan meyve diyelim (tablonun SSRS raporları gibi diğer amaçlar için kullanıldığı veritabanında olması gerekir), bir ID ile:

1 Apple 
2 Banana 
3 Grapes

Onları kullanıcıya sunabilirim, bir tanesini seçer, FavouriteFruit olarak profilinde saklanır ve veritabanındaki kaydında bulunan ID.

İş kuralları / etki alanı mantığı söz konusu olduğunda, mantığı belirli değerlere atamak için öneriler nelerdir? Kullanıcı Üzümleri seçtiyse, fazladan bir görev yapmak istiyorum, Üzüm değerine başvurmanın en iyi yolu nedir:

// Hard coded name
if (user.FavouriteFruit.Name == "Grapes")

// Hard coded ID
if (user.FavoriteFruit.ID == 3) // Grapes

// Duplicate the list of fruits in an enum
if (user.FavouriteFruit.ID == (int)Fruits.Grapes)

veya başka bir şey?

Elbette FavouriteFruit, başvuru boyunca kullanılacağından, liste eklenebilir veya düzenlenebilir.

Birileri 'Grape'nin' Grape 'olarak yeniden adlandırılmasını isteyip istemediğine karar verebilir ve bu elbette kodlanmış dize seçeneğini bozacaktır.

Sabit kod kimliği tamamen net değildir, ancak gösterildiği gibi, hangi öğenin hızlı bir şekilde olduğunu belirlemek için bir yorum ekleyebilirsin.

Enum seçeneği, senkronizasyondan çıkabileceği için yanlış görünen veritabanından veri kopyalamayı içerir.

Neyse, yorum veya önerileriniz için şimdiden teşekkür ederiz.


1
Herkese teşekkürler: öneriler ve genel tavsiyeler gerçekten çok yararlı. @RemcoGerlich gösterim amacıyla kullanılan bir dize ve daha okunabilir kod için bir arama kodu olarak ayrı bir dize kaygılarını ayırmak senin fikrin çok iyidir.
Kate

1
Her iki dünyanın en iyisi gibi gözükse de @Mike Nakis'e önceden yüklenmiş nesnelerinize bir fikir vereceğim.
Kate

1
İlk çözümünüzde bir değişiklik önerebilirim. Tablonuzun nasıl işleneceğine ilişkin 3. sütunu içermesini sağlayın ve hangi kodun çalıştırılacağını belirlemek için bu alanı kullanın. Bir görüntüleme alanı değil ve birden fazla meyve arasında paylaşılabilir.
Kickstart

1
Enum seçeneği, senkronizasyondan çıkabileceği için yanlış görünen veritabanından veri kopyalamayı içerir. Aslında bunu beğendim. Çift girişli defter tutma gibi. Defterin her iki tarafı da denge sağlamazsa bir şeyin yanlış olduğunu bileceksiniz. Değişen şeyleri daha kasıtlı hale getirir.
radarbob

1
Hmmm ... Bir String ile 1: 1 arasında ID ilişkisi varsa, o zaman bu gereksizdir ve her ikisine de sahip olmak anlamsızdır. Bir String, bir tamsayı kadar bir DB anahtarı olarak da kullanılabilir. MyApplication.Grape.IDkekemelik yapıyor, tabiri caizse. Bir "Elma", 3'ten daha fazla kimlik numarası olmayan "Red_Apple" de değildir. Bu nedenle, "Apple" ı "Red_Apple" olarak yeniden adlandırma potansiyeli, 3'ün 4 (ve hatta 3) olduğunu beyan etmekten daha anlamlı değildir. Bir enumun noktası, sayısal DNA'sını soyutlamaktır. Bu nedenle, belki de birinin iş modellerinde tam anlamıyla bir anlamı olmayan keyfi ilişkisel DB anahtarlarının gerçekten ayrılma zamanı gelmiştir .
radarbob

Yanıtlar:


31

Her ne pahasına olursa olsun, dizeleri ve sihirli sabitleri kaçının. Tamamen söz konusu değiller, seçenek olarak bile düşünülmemeliler. Bu, sizi yalnızca tek bir uygulanabilir seçenek olarak bırakıyor gibi görünüyor: tanımlayıcılar, yani enums. Ancak bence en iyisi olan bir seçenek daha var. Bu seçeneğe "Önceden Yüklenmiş Nesneler" diyelim. Önceden Yüklenmiş Nesnelerle, aşağıdakileri yapabilirsiniz:

if( user.FavouriteFruit.ID == MyApplication.Grape.ID )

Burada olan şey, açık bir şekilde tüm satırı Grapebelleğe yükledim, bu yüzden kimliğini karşılaştırmalarda kullanmaya hazırım. Nesne İlişkisel Eşleme (ORM) kullanıyorsanız, daha da iyi görünür:

if( user.FavouriteFruit == MyApplication.Grape )

(Bu yüzden "Önceden Yüklenmiş Nesneler" olarak adlandırıyorum.)

Bu nedenle, başlangıç ​​sırasında tüm "numaralandırma" tablolarımı (haftanın günleri, yılın ayları, cinsiyetler vb. Küçük tablolar) ana uygulama alanı sınıfına yüklüyorum. Onları isimle yüklüyorum, çünkü açıkça MyApplication.Grape"Üzüm" adlı satırı almalı ve her birinin bulunduğunu iddia ediyorum. Aksi halde, başlatma sırasında, tüm çalışma zamanı hatalarının en az zararı olan garantili bir çalışma zamanı hatamız vardır.


17
Cevabı kabul etmiyorum, ama bence "Her ne pahasına olursa olsun sihirli sabitlerden kaçın" zorunluluğu, gerçekte sihirli sabitlerin veya dizgelerin kullanıldığı en az bir yere sahip olmanızı gerektiren yanıtın geri kalanıyla uyuşmuyor. "önceden yüklenmiş nesnelerinizi" doldururken Orada Çünkü bence dikkate değer özellikleri olan tamamen "dizeleri ve sihirli sabitleri" kaçınmanın yolları genellikle daha 's yetmeyecek kadar obfuscating olsa ...
svidgen

2
@svidgen, her yere isimlendirme yoluyla ciltleme arasında yalnızca bir kez isimlendirme, aynı ismi taşıyan bir kaydın içeriğini yüklemek ve yalnızca bunu yapmak arasında temel bir fark olduğunu kabul etmiyor musunuz? başlangıçta çalışma zamanı hatalarının derleme hataları kadar iyi huylu olduğu durumlarda? Her neyse, adı geçen en ufak bir bağdan bile kaçınmanın yolları, bahsettiğiniz şaşkınlığa rağmen, her zaman ilginçtir, bu yüzden aklınızdakileri duymak merak ediyorum.
Mike Nakis

Oh, tamamen katılıyorum. Ve OP'nin niteliği göz önüne alındığında, bu cevabın ancak "ne pahasına olursa olsun ve mümkün olduğunda" veya "ne pahasına olursa olsun" olarak değiştirilmesinden ya da benzer bir şeyden faydalanabileceğini düşünmüştüm. ... Daha fazla zamanım olsaydı, sadece tamamlık uğruna, bir çeşit metaprogramming saçmalığıyla ilgilenen bir cevap yazardım ... ama OP (ya da çoğu durumda birinin) ihtiyacı olan şey bu değildi. . Ancak, bir metaprogamming çözümü ilk ifadenizle olduğu gibi daha fazla uyum sağlar.
svidgen

1
@ user469104 farkı, kimliklerin değişebileceği ve uygulama hala tüm satırları doğru şekilde yükleyecek ve tüm karşılaştırmaları doğru şekilde yapacaktır. Ayrıca, sizin gibi ne şekilde olursa olsun refactor kodu ve yeniden adlandırma satır serbesttir ve düzeltme için malzeme arayan gitmek zorunda tek yer uygulamanın başlangıcında olduğunu ve çok bariz olma eğilimindedir: Grape = fetchRow( Fruit.class, NameColumn, "Grape" ); Ve eğer yanlış bir şey yapmak, AssertionErrorsize bildiririz.
Mike Nakis

1
@grahamparks enumbir sihir dizgisinden daha fazlası olamazdı . Noktasıdır hepsi sadece tek bir yerde-adıyla bağlayıcı konsantrasyonu , başlangıç sırasında Tüm bunların doğrulama ve tipi emniyet .
Mike Nakis

7

Dizeye karşı kontrol etmek en okunaklı olanıdır, ancak iki görevi vardır: hem tanımlayıcı hem de açıklama olarak kullanılır (alakasız nedenlerle değişebilir).

Genelde her iki görevi de ayrı alanlara bölerim:

id  code    description
 1  grape   Grapes
 2  apple   Apple

Tanımın değişebileceği yerlerde ("Üzümler" yerine "Muz" değil), ancak kodun hiçbir zaman değişmesine izin verilmez.

Bu çoğunlukla, çünkü kimliklerimiz neredeyse her zaman otomatik olarak üretiliyor ve bu nedenle uygun değil. Kimlikleri özgürce seçebiliyorsanız, her zaman doğru olduklarını garanti edebilir ve bunları kullanabilirsiniz.

Ayrıca, birileri gerçekten "Üzümleri" "Üzümler" olarak ne sıklıkta düzenler? Belki bunların hiçbiri gerekli değildir.


8
Daha fazla işten çıkarma cevabı olduğunu sanmıyorum ...
Robbie Dee

4
Bu seçeneği de düşündüm ve denedim, ama olan bu oldu: bir noktada, "elma", "green_apple" ve "red_apple" olarak ayırt edilmek zorunda kaldı. Fakat “apple” kodun sayısız yerinde zaten kullanıldığından, onu yeniden adlandıramadım, bu yüzden “apple” ve “green_apple” almak zorunda kaldım. Sonuç olarak, içimdeki Sheldon oraya girene kadar birkaç gece uyumamı engelledi ve her şeyi "Önceden Yüklenmiş Nesneler" olarak yeniden düzenledi. (cevabımı görün.)
Mike Nakis

1
Önceden Yüklenmiş Nesnelerinizden kesinlikle hoşlanıyorum, ancak "elmanınız" farklılaştırılmışsa, ne olursa olsun, hangi yöntemi seçerseniz seçin?
RemcoGerlich

Uluslararasılaştırmayı desteklemek için açıklama adı için ayrı bir tablonuz bile olabilir.
Erik Eidt,

1
@MikeNakis ve Refactoring, esas olarak Fruit.Apple'ı Fruit.GreenApple ile değiştiren tüm Codebase'iniz üzerinde bir Ara ve Değiştir. Eğer Hardcoded String değerlerini kullanırsam, "apple" 'yı aynı şey olan "green_apple" ile değiştirmek için tüm Codebase üzerinde bir Arama ve Değiştirme yapacağım. - Yenileme daha iyi hissettiriyor, çünkü IDE Değişimi yapıyor.
Falco,

4

Burada beklediğiniz şey, değişen verilere otomatik olarak uyarlanabilen programlama mantığıdır. Enum gibi basit statik seçenekler burada çalışmaz, çünkü çalışma zamanına ek olarak sayılar ekleyemezsiniz.

Gördüğüm birkaç desen:

  • Programınızın gününü mahvedecek yepyeni bir veritabanı girişine karşı koruma sağlamak için Enums + default.
  • Veritabanında yapılacak işlemlerin kodlanması (biz mantık). Birçok durumda bu çok olasıdır çünkü birçok mantık yeniden kullanılır. Mantığın uygulanması programda olmalıdır.
  • Programın doğru konuşlanana kadar yepyeni değerini programda "yoksayılacak" olarak işaretlemek için veritabanındaki ekstra özellikler / sütunlar.
  • Veritabanından değerleri yükleyen / yeniden yükleyen kod yolunun çevresindeki hızlı mekanizmalar. (İlgili eylem programda değilse VE ihmal edilmek üzere işaretlenmediyse, yenilemeyi yapmayın).

Genel olarak, verinin, eylemlerin kendileri başka bir yerde de uygulanabilse bile, ima ettiği eylemlere gönderme anlamında eksiksiz olmasını seviyorum. Verilerden bağımsız eylemleri belirleyen herhangi bir kod, muhtemelen muhtemelen birbirinden ayrılacak ve hatalara yol açacak olan veri gösterimini paylaştı.


4

Bunları her iki yerde (bir tabloda ve bir ENUM'de) saklamak o kadar da kötü değil. Sebep şu:

Bunları bir veritabanı tablosuna kaydederek, veritabanındaki referans bütünlüğünü yabancı anahtarlar aracılığıyla zorlayabiliriz. Yani bir kişiyi veya meyveyi ne tür bir varlık ile ilişkilendirirseniz, bu sadece veritabanı tablosunda bulunan bir meyvedir.

Bunları bir ENUM olarak saklamak da anlamlıdır çünkü sihirli dizeler olmadan kod yazabiliriz ve bu kodu daha okunaklı hale getirir. Evet, senkronize olmaları gerekir, ancak ENUM'a bir satır ve veritabanına yeni bir insert ifadesi eklemek ne kadar zor olurdu.

Bir ENUM tanımlandıktan sonra değeri değiştirmez. Örneğin, eğer olsaydı:

  • elma
  • Üzüm

Grape'yi Grapes olarak değiştirmeyin. Basitçe yeni bir ENUM ekleyin.

  • elma
  • Üzüm
  • üzüm

Verileri taşımanız gerekirse, tüm Üzümleri Üzümlere taşımak için bir güncelleme uygulayın.


Başka bir adım olarak, kullanılmaması gerektiğini göstermek için meta veri değerlerinin tablodaki bir silme bayrağına sahip olduğu dükkanlarda çalıştım (kullanımdan kaldırıldıklarını veya daha yeni bir sürüm bulunduğunu).
Robbie Dee

1

Bu soruyu sormakta haklısın, yanlış koşulların değerlendirilmesine karşı savunma yapmaya çalışırken aslında güzel bir soru.

Bununla birlikte, değerlendirmenin ( ifşartlarınız) mutlaka etrafından nasıl geçeceğinizin odağı olması gerekmez. Bunun yerine, 'senkronizasyon dışı' sorununa neden olacak değişiklikleri yayma biçiminize dikkat edin.

Dize Yaklaşımı

Dizeleri kullanmanız gerekiyorsa, listeyi UI aracılığıyla değiştirme işlevini neden göstermiyorsunuz? Sistemi , örneğin, şu anda başvuruda bulunan tüm kayıtları güncelledikten sonra değiştirecek Grapeşekilde tasarlayın .GrapesGrape

Kimlik Yaklaşımı

Bazı okunabilirliklerin uzlaşmasına rağmen her zaman bir kimliğe başvurmayı tercih ederim. The list may be added toBöyle bir UI özelliğini ortaya çıkarırsanız, size bildirilecek bir şey olabilir. Kimliği değiştiren öğelerin yeniden sıralanması ile ilgileniyorsanız, böyle bir değişikliği tekrar tüm bağımlı kayıtlara yayın. Yukarıdakilere benzer şekilde. Başka bir seçenek (uygun normalizasyon kurallarını takip ederek, bir enum / id sütununa sahip olmak ve - FruitDetailarayabileceğiniz bir "Sipariş" sütununa sahip daha ayrıntılı bir tabloya başvurmak olacaktır ).

Her iki durumda da, listenizdeki değişikliği veya güncellemeyi kontrol etmeyi önerdiğimi görebilirsiniz. Bunu bir ORM veya başka bir veri erişimi kullanarak yapıp yapmadığınız, teknolojinizin özelliklerine göre belirlenir. Esasen yaptığınız şey, bu tür değişiklikler için DB'den uzak olan insanlara - ki bence sorun değil. Çoğu ana CRM aynı şartı sağlayacaktır.


1
Veritabanında , sayısal kimliği özellikle bu sorunu önlemek için alt kayıtlar için saklanmaktadır. Bu soru, bir programlama diline nasıl arayüz ekleneceği ile ilgilidir.
Clockwork-Muse

1
@ Clockwork-Muse - hangi sorunu önlemek için? Bu mantıklı değil.
JᴀʏMᴇᴇ

Kimlik yaklaşımını biraz kullanıyorum, ancak kimlik kilitlendi ve değiştirilemiyor. Ekli elbette, insanlar genellikle "kamyon" un bir şeyleri "kamyon" haline getirmekten hoşlanırken, şey (ID ile temsil edilen) değişmez.
Brian Knoblauch,

Kimlik yaklaşımı ile giderseniz, gelişim veritabanına karşı geliştirme ile nasıl başa çıkıyorsunuz? Otomatik artan ID'lerde, her iki DB'ye farklı sırayla öğe eklemek farklı ID'lerle sonuçlanacaktır.
Koruyucu bir

Yine de otomatik artış olması gerekmez mi? Bu durumda olmamalıdır, özellikle de kullandığımız enum değerinin tamsayı değeri ise.
JᴀʏMᴇᴇ

0

Çok yaygın bir problem. Veri müşteri tarafını çoğaltmak DRY ilkelerini ihlal ediyor gibi görünse de , bu gerçekten katmanlar arasındaki paradigma farkından kaynaklanmaktadır.

Enum (ya da her neyse) veritabanı ile adım dışında olması da bu kadar nadir değildir. Henüz istemci tarafı kodunda kullanılmayan yeni bir raporlama özelliğini desteklemek için bir meta veri tablosuna başka bir değer vermiş olabilirsiniz.

Bazen başka türlü de olur. İstemci tarafına yeni bir enum değeri eklenir, ancak DB güncelleştirmesi, DBA'nın değişiklikleri uygulayabileceği süreye kadar gerçekleşemez.


Evet, sorunu tanımladınız. Senin çözümün nedir
Koruyucu bir

1
Orada farz @Protectorone olan benim durumumda hatalı bir varsayımdır bir gümüş kurşun çözüm. Umut edebileceğiniz en iyi şey, bazı işletmelerin sorunlu alana sahip olmalarıdır, böylece en azından hangi tarafın geciktiğini görebilirsiniz - müşteri tarafı veya veritabanı tarafı. Bankacılık ve finans, perakende sektörü gözle görülür şekilde daha az olması nedeniyle bu konuda genellikle çok etkilidir ...
Robbie Dee

0

Temelde statik bir arama olan şeyden bahsettiğimizi varsayarsak, üçüncü seçenek olan - enum - temelde tek aklı başında seçimdir. Eğer veritabanı dahil olmasaydı ne yapardın, mantıklı geliyordu.

Daha sonra soru, veritabanında numaralandırmaların ve statik / arama tablolarının nasıl senkronize edileceği ile ilgili bir soru haline gelir ve ne yazık ki bu henüz tam bir cevabım yok.

Seçim yaparak tüm şema bakımlarımı kod olarak yapıyorum ve bu nedenle uygulamanın bir yapısı ile beklenen bir şema sürümü arasındaki ilişkiyi koruyabilirim; yap. Daha otomatik olsaydı daha iyi olurdu (ve aynı zamanda enums'lerin ve aramaların eşleşmesinin de yardımcı olmasını sağlamak için otomatik bir entegrasyon testi) ama bu daha önce uyguladığım bir şey değil.


1
Bunların sadece statik aramalar olduğuna inanmıyorum, aksi takdirde veritabanından çıkarılıp olduğu gibi tüketilebiliyor. Anladığım kadarıyla sorun, kullanılan arama değerine bağlı olarak iş mantığının ne zaman uygulanması gerektiğidir. Ancak, bu bir yana, evet - genel olarak bu amaç için kullanılır.
Robbie Dee

Tamam, daha iyi bir terime ihtiyacım var "statik arama için", tanımladığım içerik, ne demek istediğimdir :) Anahtar "statik" - bunlar, sorunu değiştirmeyen değerlerdir, yeni değerler ekliyor ve "etiketi" değiştiriyorlar ( ama niyeti değil) mevcut değerler için.
Murph
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.