ORM和图层

5 c# orm design-patterns

对不起,这一点到处都是......但是我觉得自己像一条狗在追逐我的尾巴而且我在这一点上都很困惑.

我正在尝试看到开发3层解决方案(IL,BL,DL)的最简洁方法,其中DL使用ORM来抽象对数据库的访问.

在我看过的每个地方,人们使用LinqToSQL或LLBLGen Pro生成表示数据库表的对象,并在所有3个层中引用这些类.似乎已经忽略了40年的编码模式 - 或者发生了范式转换,我错过了解释部分,为什么它完全可以这样做.

然而,似乎还有一些基础要求数据存储机制不可知 - 看看LinqToSQL刚刚发生了什么:很多代码是针对它编写的 - 只有MS才能放弃它...所以我想我尽可能地隔离ORM部分,只是不知道如何.

所以,回到绝对基础,这里是我希望以非常干净的方式组装的基本部分:

我开始的程序集:UL.dll BL.dll DL.dll

主要课程:

Message类,其具有公开MessageAddress对象的集合(称为MessageAddresses)的属性:

class Message 
{
    public MessageAddress From {get;}
    public MessageAddresses To {get;}
}
Run Code Online (Sandbox Code Playgroud)

每层功能:

BL向UI公开一个名为GetMessage(Guid id)的UI,它返回一个Message实例.

BL反过来包裹DL.

DL有一个ProviderFactory,它包装了一个Provider实例.DL.ProviderFactory公开(可能是我的一部分问题)两个名为GetMessage(Guid id)的静态方法,以及SaveMessage(消息消息)最终目标是能够换出为Linq2SQL编写的提供程序一个用于LLBLGen Pro,或另一个不支持ORM的提供商(例如VistaDB).

设计目标:我想要分层.我希望每个图层都只依赖于它下面的图层,而不是它上面的图层.我希望ORM生成的类只在DL层中.我希望UL与BL共享Message类.

因此,这是否意味着:

a)消息在BL中定义b)DB表中的Db/Orm/Manual表示('DbMessageRecord',或'MessageEntity',或其他任何ORM调用它)在DL中定义.c)BL依赖于DL d)在调用DL方法之前,没有ref或知道BL,BL必须将它们转换为BL实体(例如:DbMessageRecord)?

UL:

Main() 
{
    id = 1;
    Message m = BL.GetMessage(id);
    Console.Write (string.Format("{0} to {1} recipients...", m.From, m.To.Count));
}
Run Code Online (Sandbox Code Playgroud)

BL:

static class MessageService 
{ 
    public static Message GetMessage(id)
    {
        DbMessageRecord message = DLManager.GetMessage(id);
        DbMessageAddressRecord[] messageAddresses = DLManager.GetMessageAddresses(id);

        return MapMessage(message, 
    }

    protected static Message MapMessage(DbMessageRecord dbMessage. DbMessageAddressRecord[] dbAddresses)
    {
        Message m = new Message(dbMessage.From);
        foreach(DbMessageAddressRecord dbAddressRecord in dbAddresses){
        m.To.Add(new MessageAddress (dbAddressRecord.Name, dbAddressRecord.Address);
    }
}
Run Code Online (Sandbox Code Playgroud)

DL:

static class MessageManager 
{
    public static DbMessageRecord GetMessage(id);
    public static DbMessageAddressRecord  GetMessageAddresses(id);
}
Run Code Online (Sandbox Code Playgroud)

问题:a)显然这迟早会有很多工作.b)更多错误c)更慢d)由于BL现在依赖于DL,并且正在引用DL中的类(例如DbMessageRecord),似乎因为这些是由ORM定义的,所以你不能撕掉一个Provider,并替换它与另一个,......这使得整个练习毫无意义......也可以通过BL使用ORM的类.e)或者......在BL和DL之间需要另一个组件,并且需要另一个映射以使BL独立于底层DL类.

希望我可以更清楚地问问题......但我现在真的只是迷失了.任何帮助将不胜感激.

Bra*_*tti 2

这有点乱,让我想起了我第一次尝试 Orm 和 DDD。我个人使用核心域对象、消息传递对象、消息处理程序和存储库。因此,我的 UI 向处理程序发送一条消息,该处理程序又通过存储库水合我的对象并执行该域对象中的业务逻辑。我使用 NHibernate 进行数据访问,使用 FluentNHibernate 进行类型化绑定,而不是松散的 goosey .hbm 配置。

因此,消息传递是我的 UI 和处理程序之间共享的全部内容,并且所有 BL 都在域中。

我知道我可能会因为我的解释而受到惩罚,如果不清楚,我稍后会辩护。

就我个人而言,我不太喜欢代码生成的对象。

我必须继续添加这个答案。尝试将您的消息传递视为命令,而不是代表数据库的数据实体。我将给你举一个我的一个简单课程的例子,以及一个对我来说非常有效的基础设施决策,但我不能将其归功于:

[Serializable]
public class AddMediaCategoryRequest : IRequest<AddMediaCategoryResponse>
{
    private readonly Guid _parentCategory;
    private readonly string _label;
    private readonly string _description;

    public AddMediaCategoryRequest(Guid parentCategory, string label, string description)
    {
        _parentCategory = parentCategory;
        _description = description;
        _label = label;
    }

    public string Description
    {
        get { return _description; }
    }

    public string Label
    {
        get { return _label; }
    }

    public Guid ParentCategory
    {
        get { return _parentCategory; }
    }
}

[Serializable]
public class AddMediaCategoryResponse : Response 
{
    public Guid ID;
}


public interface IRequest<T> : IRequest where T : Response, new() {}


[Serializable]
public class Response
{
    protected bool _success;
    private string _failureMessage = "This is the default error message.  If a failure has been reported, it should have overwritten this message.";
    private Exception _exception;

    public Response()
    {
        _success = false;
    }

    public Response(bool success)
    {
        _success = success;
    }

    public Response(string failureMessage)
    {
        _failureMessage = failureMessage;
    }

    public Response(string failureMessage, Exception exception)
    {
        _failureMessage = failureMessage;
        _exception = exception;
    }

    public bool Success
    {
        get { return _success; }
    }

    public string FailureMessage
    {
        get { return _failureMessage; }
    }

    public Exception Exception
    {
        get { return _exception; }
    }

    public void Failed(string failureMessage)
    {
        _success = false;
        _failureMessage = failureMessage;
    }

    public void Failed(string failureMessage, Exception exception)
    {
        _success = false;
        _failureMessage = failureMessage;
        _exception = exception;
    }
}


public class AddMediaCategoryRequestHandler : IRequestHandler<AddMediaCategoryRequest,AddMediaCategoryResponse>
{
    private readonly IMediaCategoryRepository _mediaCategoryRepository;
    public AddMediaCategoryRequestHandler(IMediaCategoryRepository mediaCategoryRepository)
    {
        _mediaCategoryRepository = mediaCategoryRepository;
    }

    public AddMediaCategoryResponse HandleRequest(AddMediaCategoryRequest request)
    {
        MediaCategory parentCategory = null;
        MediaCategory mediaCategory = new MediaCategory(request.Description, request.Label,false);
        Guid id = _mediaCategoryRepository.Save(mediaCategory);
        if(request.ParentCategory!=Guid.Empty)
        {
            parentCategory = _mediaCategoryRepository.Get(request.ParentCategory);
            parentCategory.AddCategoryTo(mediaCategory);
        }
        AddMediaCategoryResponse response = new AddMediaCategoryResponse();
        response.ID = id;
        return response;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这种情况会一直持续下去,但这个基本系统在过去一年左右的时间里对我很有帮助

您可以看到处理程序允许域对象处理域特定逻辑