Kullanıcı tanımlı alanlara izin vermek kötü bir uygulama mı?


17

Genel olarak konuşursak, bir webapp için bir veritabanında kullanıcı tarafından oluşturulan alanlara izin vermek kötü uygulama olarak kabul edilir mi?

Örneğin, eşim için bir ev envanteri web uygulaması yapıyorum ve farklı öğeler için kendi alanlarını tanımlamak isteyecek. Öğe kategorileri oluşturmasına ve bu kategorilere "özellikler" eklemesine izin vermeyi planlıyordum. Özellikler sadece anahtar / değer dizeleri olarak saklanır. Bu şekilde, örneğin "Ses CD'leri" adlı bir kategoriye sahip olsaydı, "sanatçı", "şarkılar" gibi şeyler için özellikler ekleyebilirdi. Ancak, "mobilya" gibi bir kategoriye "malzeme" gibi özellikler ekleyebilirdi "(ahşap, plastik vb.). Ardından, herhangi bir öğe, bu özellikleri öğeye ekleyerek bir (veya birçok) kategoriye ait olabilir.

Bu özelliklerle aramanın dize karşılaştırmaları gerektirdiği, verilerin doğrulanamadığı vb. Sorunları görebiliyorum. Çevik metodolojiyi takip ederek, belki de sadece yeni kategoriler ve niteliklerle gelmesi daha iyi olurdu ve sadece yeni tablolar oluşturmak zorunda kalacağım. Biz devam ederken. Örneğimde, küçük bir kullanıcı tabanı (ikimiz) ve oluşturulan kayıtların miktarı küçük olurdu, bu yüzden çok kötü değil.

Genel olarak konuşursak, insanlar "gerçek hayatta" böyle bir şeyi nasıl ele alırlar?


4
MongoDB gibi belge odaklı bir veritabanı kullanmayı düşündünüz mü? Düzenlenebilecek bir şema görevi gören her türden bir belgeyi saklayabilirsiniz (muhtemelen projenin küçük ölçeği göz önüne alındığında).
Andy Hunt

@AndyBursh mevcut postgres ile 'eğlenceli' bitlerden biri 'json' veri türüdür ( bağlantı ). Böyle bir yaklaşım, kullanıcının belirlediği alanları bu veri, er, belge, er, ne olursa olsun depolamasına ve daha sonra alanların geri kalanını uygun indekslerin ve benzerlerinin ne olduğu için kullanmasına izin verecektir. Her ne kadar hepsi kullanıma bağlıdır ve bunun belirli bir uygulama için iyi çalışıp çalışmadığını söylemek zor. Ama bunun farkında olması gereken bir şey.

hepsi: büyük tartışma, tüm içgörü için teşekkürler! @AndyBursh MongoDB'yi duydum ama gerçekten hiç okumadım.
Denemek

Yanıtlar:


19

Hata izleyicilerinde, müşteri kaynak yönetiminde ve benzer iş araçlarında sıkça bulunan "kullanıcı tanımlı alanlara" ulaşmaya başladığınızda, bunların bajillion alanlarına sahip bir tablo ile desteklenmemeleridir (eğer öyleyse, muhtemelen Kendi).

Bunun yerine, var olan Öznitelik Değeri tablosu tasarımları ve geçerli öznitelikleri yönetmek için ilişkili yönetim aracı bulunur.

Aşağıdaki tabloyu düşünün:

  + -------------- +
  | şey |
  | -------------- |
  | id |
  | türü |
  | desc |
  | attr1 |
  | attr2 |
  | attr3 |
  | attr4 |
  | attr5 |
  + -------------- +

Bu, birkaç özellik ekledikten sonra. Okuyormuş attr1gibi davranmak yerine, artistya tracksda genreya da her şeyin niteliği ne olursa olsun. Ve 5 yerine, ya 50 olsaydı. Açıkça bu yönetilemez. Ayrıca, yeni bir alanı işlemek için modelin güncellenmesini ve uygulamanın yeniden dağıtılmasını gerektirir. Uygun değil.

Şimdi aşağıdaki tablo yapısını düşünün:

  + -------------- + + --------------- + + ------------- +
  | şey | | thing_attr | | attr |
  | -------------- | | --------------- | | ------------- |
  | id | <--- + | thing_id (fk) | +> | id |
  | türü | | attr_id (fk) | + - + | adı |
  | desc | | değeri | | |
  + -------------- + + --------------- + + ------------- +

Temel alanları ile her şeye sahipsiniz. İki tablonuz daha var. Özniteliklere sahip biri. Her alan attrtablodaki bir satırdır . Ve sonra masa ve masa thing_attrile ilgili bir çift yabancı anahtar var . Ve sonra, bu varlık için alanın değeri ne olursa olsun depoladığınız bir değer alanı vardır.thingattr

Ve şimdi attr tablosunun çalışma zamanında güncellenebileceği ve genel uygulamaya önemli bir etki yapmadan anında yeni alanların eklenebileceği (veya kaldırılabileceği) bir yapınız var.

Sorgular biraz daha karmaşıktır ve doğrulama da daha karmaşık hale gelir (korkak saklı yordamlar veya tüm istemci tarafı). Tasarımda bir takas.

Ayrıca, bir gün bir geçiş yapmanız gereken ve şimdi ilk dağıttığınız şemadan yarım düzine kadar daha fazla özellik olduğunu bulmak için uygulamaya geri döndüğünüz durumu da düşünün. Bu, doğru şekilde kullanıldığında Varlık Özellik Değeri tablosunun daha temiz olabileceği çirkin geçişler ve yükseltmeler yapar. (Her zaman değil, ama olabilir.)


Çalışma zamanında şemayı değiştirmenin herhangi bir dezavantajı var mı? Kullanıcı bir şeyin yeni bir niteliğe ihtiyacı olduğunu düşünüyorsa, tabloya dinamik olarak bir sütun eklensin mi?

Eğer nosql veritabanının uygun lezzeti ile çalışıyorsanız, muhtemelen bunu yapabilirsiniz (bunun için nosql'in uygun lezzetinin muhtemelen yukarıda açıklanan ilişkisel olanlar için EAV tablosu olan bir anahtar / değer deposu olacağını unutmayın ) çok fazla sorun olmadan. Bununla birlikte , başka bir yerde ayrıntılı olarak açıklanan nosql için tüm tavizlerle birlikte gelir.

Bunun yerine ilişkisel bir veritabanı üzerinde çalışıyorsanız - şemaya sahip olmanız gerekir. Sütunu dinamik olarak eklemek, aşağıdakilerin bazı alt kümelerinin doğru olduğu anlamına gelir:

  • Meta-veritabanı programlama yapıyorsunuz. Bu sütunu güzel bir ORM ile o alana temiz bir şekilde eşlemek yerine, muhtemelen select *verilerin gerçekte ne olduğunu bulmak için bazı karmaşık kodlar yapıyor ve daha sonra karmaşık bir kod yapıyorsunuz (bkz. Java'nın ResultSetMetaData ) ve ardından bunu bir haritada ( veya başka bir veri türü - ancak koddaki hoş alanlar değil ). Bu, daha sonra geleneksel yaklaşımla sahip olduğunuz adil tip ve yazım güvenliğini ortadan kaldırır.
  • Büyük olasılıkla ORM'den vazgeçtiniz. Bu, sistemin işi sizin için yapmasına izin vermek yerine tüm kodlar için ham sql yazdığınız anlamına gelir.
  • Temiz yükseltmeler yapmaktan vazgeçtiniz. Müşteri, bir sonraki sürümünüzün de kullandığı bir adla bir alan eklediğinde ne olur? Eşleştirme sitesinde, hasdatezaman damgasını saklamak için bir alan eklemek isteyen yükseltme, hasdatebaşarılı bir maç için bir boole ile tanımlanmıştı ... ve yükseltme molalarınız var.
  • Müşterinin, sorgunuzu da kıran bazı ayrılmış sözcükleri kullanarak sistemi kırmamasına güveniyorsunuz ... bir yerde.
  • Kendinizi bir veritabanı markasına bağladınız. DDL farklı veritabanlarının farklıdır. Veritabanı türleri bunun en kolay örneğidir. varchar2vs textve benzerleri. Sütunu ekleme kodunuz MySQL üzerinde çalışır ancak Postgres veya Oracle veya SQL Server'da çalışmaz.
  • Müşteriye verileri gerçekten iyi eklemesi için güveniyor musunuz ? Elbette, EAV ideal olmaktan uzaktır, ancak şimdi geliştiricinin eklemediği bazı yanlış karanlık tablo isimleriniz var, yanlış dizin türüyle (varsa), kodda herhangi bir kısıtlama eklenmediğinde olmak vb.
  • Uygulamayı çalıştıran kullanıcıya şema değişikliği ayrıcalıkları verdiniz. DDL yerine SQL ile sınırlı olduğunuzda Little Bobby Drop Tables mümkün değildir ( delete * from studentsbunun yerine emin olabilirsiniz , ancak veritabanını gerçekten kötü şekillerde bozamazsınız). Bir kazadan veya kötü amaçlı etkinliklerin patladığı şema erişimiyle yanlış gidebilecek şeylerin sayısı.

Bu gerçekten "yapma" der. Bunu gerçekten istiyorsanız, EAV tablo yapısının bilinen bir deseni veya tamamen bu yapıya adanmış bir veritabanı ile gidin. İnsanların bir tabloda rastgele alanlar oluşturmasına izin vermeyin. Baş ağrıları buna değmez.


4
Ayrıca veritabanını yeniden icat ettiniz.
user253751

1
@immibis, kullanıcının veritabanının geri kalanını yönetmeden veya modeli güncellemek için yeniden dağıtım gerektirmeden yönetebileceği bir katman ekledi.

1
@immibis EAV yıllardır ilişkisel veritabanı çevrelerinde sıcak bir şekilde tartışmaktadır. Teoride gereksizdir, ancak pratikte onsuz bazı şeyler yapamazsınız.
Ross Patterson

1
@ NoSQL yaklaşımına giden ShivanDragon. Belge deposu yalnızca belgeleri depolar ve şema dayatmaz. Bu nedenle, alan ekleme ve kaldırma ve belgeleri ayrıştırma tamamen veritabanının kapsamı dışındadır (ve modelinizi buna uyacak şekilde yazdınız). Bir EAV yapısı için ilişkisel veritabanı güvenliğinden tamamen farklı bir uzlaşma kümesi.


5

Bunu iyi yapmak zor.

Planladığınız gibi bir kerelik bir uygulama için, elbette, her alan için bir sütun ekleyebilir ve eğitimsiz kullanıcılar tarafından alan tanımını SQL komut satırı vermekten daha güvenli hale getiren bir kullanıcı arayüzü sağlayabilirsiniz. Veya korkutucu Varlık-Öznitelik-Değer modelini, biraz korkutucu olsa da, bu tür bir soruna yanıt olarak izleyebilirsiniz . EAV alanlarını tanımlamak için UI oluşturmak genellikle veritabanı sütunlarından çok daha karmaşıktır ve sorgular oldukça kıllı olabilir, ancak çok sayıda alan için ( yani , çok seyrek matris şemaları), iş bitti.


Özetle: küçük proje == ÖPÜCÜK. Yere kadar çevik.
Encaitar

Veritabanı tablosu güncellemeleri ile ilgili sorun, veri miktarına ve gerekli indekslere bağlı olarak (özel alanlar genellikle arama özellikleri gerektirir), tablo değiştirme sorgusunun mamut bir süre alabilmesidir. Uzun lafın kısası, MySQL ve diğer ilişkisel veritabanlarının bu tür bir gereksinim için iyi bir araç olmadığıdır.
Oddman

0

Geçenlerde benzer bir haç geldim.

2 masa yaptım.

1: table Objects 
    Id , name, type

O tüm nesneleriniz. U adını ayarlayın.

Ve bu nesnenin bir türü: - benim için mevcut türleri envanter, envanter_öğesi, ofis oldu.

Ve her zamanki kurulum, n öğenin alt öğe veya envanter olduğu ve aynı zamanda ofisin çocuğu olduğu ve nesneleri birbirine bağlamak için bir birleştirme tablosu kullandım

2 table settings 
     organization_Id , title, value , type

Ayarlar tablosu, söz konusu nesne türü için her alan adını ve değer içindeki değeri içerir.

Ofisin örnek özellikleri

Yer, telefon, çalışma saatleri

Ve eşyalar için

  • Miktar
  • Fiyat
  • Barkod

Vb, tüm bu özellikler sizin modeliniz tarafından zorlanır ve ayarlar tablosuna ayrı satırlar olarak kaydedilir (yine de aynı alan için birden çok satırdan kaçınmak için insert insert kullanmayın)

Bu yüzden bir ofis istediğimde, object_I'd ayarların bulunduğu tüm ilişkileri ve ayarları ile kolayca yüklüyorum (istenen nesneler)

Bundan sonra tüm satırları ayarlardan döndürüyorum ve hepsi bu.

Ve bir ayar envanterinde (global değil) bir öğeye özgü olmasını istersem object_I'd = nesne_objects ilişkiler tablosundan ayarladım ve settings.type = relation_setting ayarladım

Umarım bir dizüstü bilgisayara geldiğimde cevabı yeniden biçimlendirmeye çalışacağımı anladın


2
Profesyonel ipucu - bu forumda telefonunuzdan yayın paylaşmayın. Otomatik düzeltme, yayınınızın bir kısmını okunamaz hale getirir.
BobDalgleish

Haha güzel gözlem :)
Zalaboza

0

Kullanıcı tanımlı alanlara izin vermek kötü bir uygulama mı?

Hayır, kötü bir uygulama değil. Oldukça yaygındır. OO terimleriyle buna kalıtım denir. Bir temel sınıf envanterItem ve iki miras AudioCD ve mobilya sınıfı var.

Genel olarak konuşursak, insanlar "gerçek hayatta" böyle bir şeyi nasıl ele alırlar?

EnvanterItem, AudioCD ve mobilyaların veritabanında nasıl saklanacağına karar vermelisiniz.

Kolay sorgulama sizin için en önemliyse ve db-space / normalization önemli değilse, "hiyerarşi başına tablo" şemasını uygularsınız.

Alan / normalleştirme sizin için en önemliyse ve daha karmaşık sorgular sizin için sorun değilse, "tür başına tablo" Şemasını uygularsınız.

Daha fazla ayrıntı için bkz. Dotnet table-type-type-vs-table-hiyerarşi-kalıtım veya java hazırda bekletme .


Bunun soruyu ele alıp almadığını bilmiyorum. Kullanıcı yeni sınıflar oluşturmak için kodu değiştirmiyor
Colin D
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.