【问题标题】:What is the best-practice way to use LINQ to SQL in a C# application? [Design-pattern]在 C# 应用程序中使用 LINQ to SQL 的最佳实践方法是什么? [设计模式]
【发布时间】:2010-06-21 19:11:03
【问题描述】:

好的,我一直在努力改进我的编码方式,因为这是我的热情所在。我有一个 .dbml 文件 (LINQ to SQL),我用它来访问我的 SQL Server 数据库。

想象一下,如果您愿意,您的数据库中有一个 Person 表,并且您想提供一种删除、添加和修改 Person 记录的方法。

我目前处理事情的方式是创建名为 PersonRepository、CarRepository、DocumentRepository 等的类。对于我数据库中的每个表,我创建一个存储库类。

这些存储库类通常由类似于以下内容的内容组成:

MyDatabaseContext db = new MyDatabaseContext();

public Person GetPersonByID(int id)
{
    return db.Person.Where(p => p.ID == id);
}

每个表的基本 CRUD 功能几乎相同。

如果我需要更具体的内容,例如“Sergio,我需要一份所有出生在 x 和 y 之间的人的列表”;然后我只是将方法添加到 PersonRepository 类。

public List<Person> GetPeopleFromDOB(DateTime x, DateTime y)
{
    // Do the logic here.
}

我的另一个想法是创建一个 DataAccess.cs 类并在其中包含所有这些方法(我们将讨论每个现有表大约 4-5 个方法)并按区域划分它们。

知识更渊博的程序员在做什么?对于一个热心的年轻程序员(我今年 20 岁),您有什么建议?

【问题讨论】:

    标签: c# .net linq-to-sql design-patterns


    【解决方案1】:

    以下是您在上面所做的事情的问题:

    在应该使用 IQueryable 时使用 List

    Why use AsQueryable() instead of List()?

    基本上,在您需要数据之前,您永远不应该获取数据。使用您的方法,您总是从数据库中获取数据,随后的 LINQ 查询将作用于所有数据。为什么不只是构建查询并让 LINQ 将事情细化到只在需要时才获得所需内容的地方?

    在扩展方法完美时使用方法

    您正在使用 GetPeopleFromDOB 等方法创建实用程序类。为什么不将此作为扩展方法?如果你让它们都返回 IQueryable 你也可以连续使用它们。例如。 GetPeople().StatusEnabled().BornInJuly().AgeIsGreaterThan( 57 ); 另外,如果您必须这样做,至少考虑在部分类或静态实用程序类中这样做。

    考虑使用 ActiveRecord/Repository 模式作为根

    http://compiledexperience.com/blog/posts/Implementing-an-ActiveRecord-pattern-in-Linq-to-SQL

    现在您正在创建几个硬编码的存储库,但您应该将它们基于存储库吗?

    为什么不使用验证器?

    如果您使用的是 ASP.NET MVC,则验证是必不可少的,但是对于 Web 表单,您也可以使用数据注释验证器。

    http://adventuresdotnet.blogspot.com/2009/08/aspnet-webforms-validation-with-data.html

    【讨论】:

    • (编辑:这是一个 Windows 窗体应用程序)感谢这些链接。 IQueryable 过滤数据库中的内容,而 List 过滤内存中的内容。我必须弄清楚哪个最适合我。另外,您是否有关于如何在这种情况下使用扩展方法的有用链接?
    • 我会坚持使用 IQueryable。如果您真的想要/需要在内存中执行查询,那么只需在存储库方法调用的结果上添加 .ToList() 然后进行过滤。 (编辑:这是制作“Fluent”L2S 扩展方法的链接。blog.sb2.fr/post/2009/01/03/…
    • 给你,注意他们有 IQueryable:weblogs.asp.net/timothykhouri/archive/2007/09/12/… 我指出这一点是因为它是使用 LINQ to SQL 的扩展方法的一个很好的例子,并且还突出了警告。
    • 使用 ActiveRecord 模式能给我带来什么好处?我觉得它在不需要的地方增加了复杂性。如果我使用这种 SingleRepository 方法,添加的功能会容易得多,并且代码会更自然地调用“PersonRepository.FindPeople()、.FindPerson()、FindWomen()、FindMen() 等”
    • 它使数据访问通用化并在您的 DAL/BLL 中创建一致性。此外,它还抽象出数据访问,并允许您轻松地将底层数据层切换到其他技术,例如 Entity Framework 或 NHibernate。
    【解决方案2】:

    我会坚持使用single responsibility principle 并坚持使用您的存储库类。如果您的数据库随着时间的推移而增长,想象一下 DataAccess 类会变得有多大。你会暂时摆脱它,但它会不断增长,直到你在一个类中有数千行代码(我以前在这样的一个类中看到过 15000 多行代码)并且你被卡住了!

    【讨论】:

    • 天哪。 15,000?我为必须维持这一点的人感到难过。
    【解决方案3】:

    您需要使用 存储库 来使用 L2S 直接连接您的 DBML。

    然后您需要创建一个与您的存储库通信的服务

    最后,您将在 code-behind 或 MVC 控制器等方面使用该服务。

    用户存储库

    Namespace Data
    
    #Region "Interface"
        Public Interface IUserRepository
            Function GetAllUsers() As IList(Of User)
            Function GetUserByID(ByVal id As Integer) As User
        End Interface
    #End Region
    
    #Region "Repository"
        Public Class UserRepository : Implements IUserRepository
            Private dc As MyDataContext
            Public Sub New()
                dc = New MyDataContext
            End Sub
    
            Public Function GetAllUsers() As System.Collections.Generic.IList(Of User) Implements IUserRepository.GetAllUsers
                Dim users = From u In dc.Users
                            Select u
                Return users.ToList
            End Function
    
            Public Function GetUserByID(ByVal id As Integer) As User Implements IUserRepository.GetUserByID
                Dim viewUser = (From u In dc.Users
                           Where u.ID = id
                           Select u).FirstOrDefault
                Return viewUser
            End Function
    
        End Class
    #End Region
    End Namespace
    

    用户服务

    Namespace Data
    
    #Region "Interface"
        Public Interface IUserService
            Function GetAllUsers() As IList(Of User)
            Function GetUserByID(ByVal id As Integer) As User
        End Interface
    #End Region
    
    
    #Region "Service"
        Public Class UserService : Implements IUserService
    
            Private _ValidationDictionary As IValidationDictionary
            Private _UserRepository As IUserRepository
    
            Public Sub New(ByVal validationDictionary As IValidationDictionary, ByVal UserRepository As IUserRepository)
                _ValidationDictionary = validationDictionary
                _UserRepository = UserRepository
            End Sub
    
            Public Function GetAllUsers() As System.Collections.Generic.IList(Of User) Implements IUserService.GetAllUsers
                Return _UserRepository.GetAllUsers
            End Function
    
    
            Public Function GetUserByID(ByVal id As Integer) As User Implements IUserService.GetUserByID
                Return _UserRepository.GetUserByID(id)
            End Function
    
        End Class
    #End Region
    End Namespace
    

    现在只需确保像上面提到的那样使用CRUD

    另外,请原谅我的VB。您可能需要通过http://converter.telerik.com 代码转换器运行它以获取 C# 内容。

    【讨论】:

    • 我不明白您在这里服务的目的。您似乎只是在包装存储库方法而没有实际添加任何值。验证字典有什么作用?您是否有可以分享的链接来解释有关此模式的更多信息?谢谢。
    猜你喜欢
    • 2011-02-16
    • 1970-01-01
    • 2014-03-07
    • 2014-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    相关资源
    最近更新 更多