denetleyicinin servis yerine depo çağrısı mı kötü bir uygulama?


43

denetleyicinin servis yerine depo çağrısı mı kötü bir uygulama?

daha fazla açıklamak için:

İyi tasarım denetleyicilerinde servis ve servis kullanım havuzunu çağırdığımı anladım.

ama bazen denetleyicide herhangi bir mantığa ihtiyacım yok / ihtiyacım yok ve sadece db'den alıp görüntülemek için geçmem gerekiyor.

ve sadece depoyu arayarak yapabilirim - servisi aramaya gerek yok - kötü bir uygulama mı?


Servisi nasıl arıyorsun? Bir REST arayüzü ile?
Robert Harvey,

2
Bu tasarım yaklaşımını oldukça sık kullanıyorum. Denetleyicim (veya altında yatan bir besteci sınıfı), veri deposundan veri ister veya depoya veri gönderir ve ardından işlem yapması gereken tüm hizmet sınıflarına geçirir. Veri işleme sınıflarını veri alma / yönetim sınıflarıyla birleştirmenin bir nedeni yoktur, tipik yaklaşımın bu şekilde yapmak olduğunu bilsem de farklı endişelerdir.
Jimmy Hoffa,

3
Meh. Küçük bir uygulamaysa ve yalnızca bir veritabanından veri almaya çalışıyorsanız, bir servis katmanı, REST arayüzü gibi bazı genel API’lerin bir parçası olmadıkça , zaman kaybıdır . "Süt sizin için iyi midir yoksa sizin için kötü mü?" Laktoz intoleransı yapmanıza bağlı olarak değişir.
Robert Harvey,

4
Controller -> Repository üzerinden bir Controller -> Service -> Repository yapısına sahip olmanız gereken zor ve hızlı bir kural yoktur. Doğru uygulama için doğru modeli seçin. Söyleyeceğim şey, başvurunuzu tutarlı hale getirmeniz gerektiği.
NikolaiDante

Belki de isteğinizi yalnızca depoya yönlendiren ve ardından geri dönen bir genel hizmet bulursunuz. Bu, düzgün bir arayüz oluşturmak için faydalı olabilir ve gelecekte depoyu çağırmadan önce bir şeyler yapmak için gerçek bir servis eklemeniz gerekirse basit olacaktır.
Henrique Barcelos,

Yanıtlar:


31

Hayır, şu şekilde düşünün: bir depo bir hizmettir (ayrıca).

Depodan aldığınız varlıklar işletme mantığının çoğunu işliyorsa, başka hizmetlere gerek yoktur. Sadece depoya sahip olmak yeterli.

Varlıklarınızı değiştirmek için geçirmeniz gereken bazı hizmetler olsa bile. Önce depodan işletmeyi alın ve ardından söz konusu hizmete aktarın. Denemeden önce bir HTTP 404'ü fırlatabilmek çok uygundur.

Ayrıca okuma senaryosunun yaygın olması için, sadece onu bir DTO / ViewModel'e yansıtması için varlığa ihtiyacınız vardır. O zamanlar arasında bir servis katmanının olması, genellikle çirkin olan yöntemlerden çok fazla geçişle sonuçlanır.


2
İyi dedi! Tercihim depoları çağırmak ve yalnızca durumlarda, o zaman bir depo yeterli değil (yani iki varlık farklı depolar kullanılarak değiştirilmelidir), bu işlemden sorumlu bir servis oluşturup kontrol cihazından çağırırım.
Zygimantas

Sadece bir servis kullanımını haklı çıkarmak için oldukça karmaşık bir kod fark ettim.
Saçma

Bu yüzden, havuzum 'xml nesnelerine' dönüştürmem gereken 'iş nesnelerinin' bir listesini döndürüyor, bu nedenle hizmet katmanına sahip olmak yeterli mi? Her nesnede başka bir türe dönüştürmek ve yeni bir listeye eklemek için bir yöntem arıyorum.
bot_bot

Doğrudan DAO Erişimi denetleyicilerde tehlikelidir, sizi SQL enjeksiyonlarına duyarlı hale getirebilir ve ,, deleteAll '' gibi tehlikeli eylemlere erişim sağlar.
Anirudh

4

Bir kontrolörün doğrudan bir havuzu çağırması kötü bir uygulama değildir. Bir "servis" sadece başka bir araçtır, bu yüzden mantıklı olduğu yerde kullanın.

NikolaiDante yorum yaptı:

... Doğru uygulama için doğru deseni seçin. Söyleyeceğim şey, başvurunuzu tutarlı hale getirmeniz gerektiği.

Tutarlılığın en önemli yönü olduğunu sanmıyorum. Bir "servis" sınıfı, bazı üst seviye mantıkları kapsamaya yöneliktir, böylece kontrol cihazının bunu uygulamasına gerek kalmaz. Belirli bir işlem için gerekli hiçbir "üst seviye mantık" yoksa, doğrudan depoya gidin.

Ayrı Endişelerin ve Test Edilebilir Ayrımın teşvik edilmesi için, depo, bir yapıcı aracılığıyla servise enjekte ettiğiniz bir bağımlılık olmalıdır:

IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);

service.DoSomething(...);

Veritabanındaki kayıtları aramak bir tür parametreli sorguya ihtiyaç duyuyorsa, hizmet sınıfı görünüm modelinizi almak ve daha sonra depo tarafından yürütülen bir sorgu oluşturmak için iyi bir yer olabilir.

Benzer şekilde, bir form için karmaşık bir görünüm modeline sahipseniz, bir hizmet sınıfı, Etki Alanı Modelleri / Varlıklarınızdaki yöntemleri çağırarak kayıtlar oluşturma, güncelleme ve silme mantığını kapsayabilir ve daha sonra bunları bir depo kullanarak devam ettirebilir.

Eğer kontrol cihazınızın kimliği ile bir kayıt alması gerekiyorsa, ters yönlere gitmek, o zaman bunun için bir servis nesnesine yetki vermek, bir balyozla raptiye vurmak gibidir - ihtiyaç duyduğunuzdan çok daha fazlası.

İşlemi veya bir Birim Birimi nesnesini işlem yapmak için denetleyicinin en iyi konumda olduğunu buldum . Kontrolör veya Çalışma Birimi nesnesi daha sonra karmaşık işlemlerde servis nesnelerine devreder veya basit işlemler için doğrudan depoya gider (Id ile kayıt bulma gibi).

public class ShoppingCartsController : Controller
{
    [HttpPost]
    public ActionResult Edit(int id, ShoppingCartForm model)
    {
        // Controller initiates a database session and transaction
        using (IStoreContext store = new StoreContext())
        {
            // Controller goes directly to a repository to find a record by Id
            ShoppingCart cart = store.ShoppingCarts.Find(id);

            // Controller creates the service, and passes the repository and/or
            // the current transaction
            ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);

            if (cart == null)
                return HttpNotFound();

            if (ModelState.IsValid)
            {
                // Controller delegates to a service object to manipulate the
                // Domain Model (ShoppingCart)
                service.UpdateShoppingCart(model, cart);

                // Controller decides to commit changes
                store.SaveChanges();

                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }
    }
}

Bence bir hizmet karışımı ve doğrudan depolarla çalışmak tamamen kabul edilebilir. İhtiyacı hissederseniz, işlemi bir İş Birimi nesnesinde daha fazla kapsülleyebilirsiniz.

Sorumlulukların dağılımı şu şekildedir:

  • Kontrolör uygulamanın akışını kontrol eder
    • Alışveriş sepeti veritabanında değilse "404 Bulunamadı" ifadesini döndürür
    • Doğrulama başarısız olursa, formu doğrulama mesajlarıyla yeniden işler
    • Her şey kontrol edilirse alışveriş sepetini kaydeder
  • Denetleyici, Etki Alanı Modellerinizde (veya Varlıklar) iş mantığını yürütmek için bir hizmet sınıfına yetki verir. Hizmet nesneleri iş mantığını uygulamamalıdır ! Onlar yürütmek iş mantığını.
  • Kontrolörler basit işlemler için doğrudan depolara devredebilir
  • Hizmet nesneleri görünüm modelinde veri alır ve iş mantığını yürütmek için Etki Alanı Modellerine yetki verir (örn. Hizmet nesnesi, depodaki yöntemleri çağırmadan önce Etki Alanı Modellerinde yöntemleri çağırır)
  • Hizmet nesneleri veri kalıcılığı için depolara devrediyor
  • Kontrolörler şunlardan birini yapmalıdır:
    1. Bir işlemin ömrünü yönetme veya
    2. Bir işlemin ömrünü yönetmek için İş Birimi nesnesi oluşturma

1
DbContext'i bir depo yerine denetleyiciye koymak için -1. Depo veri sağlayıcılarını yönetmeyi amaçlamaktadır, böylece başka hiç kimse bir veri sağlayıcısının değişmesi durumunda (örneğin, MySQL'den düz JSON dosyalarına, bir yerde değişiklik
yapmaz

@JimmyHoffa: Aslında yazdığım koda bakıyorum ve dürüst olmak gerekirse, veri tabanlarım için veri tabanı gerektirmeyen bir "bağlam" nesnesi oluşturuyorum. DbContextBu durumda bence kötü bir isim. Bunu değiştireceğim. NHibernate kullanıyorum ve depolar (ya da kullanışlı ise bağlam) olayların sonunu yönetiyor, bu yüzden kalıcılık mekanizmalarını değiştirmek bağlam dışında kod değişikliği gerektirmiyor.
Greg Burghardt

kodunuzun görünümüyle denetleyiciyi depo ile karıştırıyor gibi görünüyorsunuz ... Yani, "bağlamınız" tamamen yanlış ve denetleyicide kesinlikle bulunmamalıdır.
Jimmy Hoffa,

6
Cevap vermek zorunda değilim ve bunun başlamak için iyi bir soru olduğundan emin değilim, ama aşağıya oy kullandım çünkü yaklaşımınızın kötü bir tasarım olduğunu düşünüyorum. Zor duygular yok, sadece kontrollerin sahip olduğu bağlamlardan vazgeçiriyorum. IMO bir denetleyici böyle bir işlem başlatmamalı ve işlem yapmamalıdır. Bu, başka herhangi bir sayıdaki yerin işidir, denetleyicileri, sadece HTTP isteğini yerine getirmeyen her şeyi başka bir yere devretmek için tercih ederim.
Jimmy Hoffa,

1
Bir depo, genellikle, etki alanının kendisinin bilmesi gerekenler dışında veri ile ilgili herhangi bir şey bilmesi gerekmediğinden tüm veri bağlamı bilgilerinden genellikle sorumludur
Jimmy Hoffa,

1

Bu senin mimarisine bağlı. Spring'i kullanıyorum ve işlem her zaman servisler tarafından yönetiliyor.

Doğrudan yazma işlemleri için depoları ararsanız (veya yalnızca basitçe havuza atanan mantığı olmayan basit hizmetler), muhtemelen bir işlemde yapılması gereken bir işlem için birkaç veritabanı işlemi kullanıyorsunuzdur. Bu veritabanınızdaki tutarsız verilere yol açacaktır. Genel bir kural olarak, veritabanı işlemleri çalışmalı ya da başarısız olmalıdır, ancak yarı çalışma işlemleri baş ağrılarının nedenidir.

Bu nedenle depoları doğrudan denetleyicilerden çağırmak veya basit temsilci hizmetleri kullanmak kötü bir uygulamadır. Sadece okumak için yapmaya başlarsınız, ve çok yakında siz veya bir veya arkadaşlarınız yazma işlemleri için yapmaya başlayacaktır.

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.