【问题标题】:How to customise properties on a Linq2SQL entity?如何自定义 Linq2SQL 实体的属性?
【发布时间】:2010-10-01 04:52:44
【问题描述】:

我知道您可以通过部分类自定义实体,但是修改实体属性的一般方法是什么?如果我想更改 get/set 中的逻辑怎么办?添加属性呢?我不想编辑自动生成的代码 - 人们如何解决这个问题?

【问题讨论】:

    标签: .net linq-to-sql


    【解决方案1】:

    根本不自动生成代码。您可以在不使用设计器的情况下构建自己的 linq to sql 类。

    编辑:我这样做的懒惰方式是自动生成代码,将其复制粘贴到未生成的文件中,然后删除设计器文件。不过由你决定。

    【讨论】:

    • 那么你如何使用Linq2SQL呢?你不能轻易地将实体从支持框架/数据上下文中分离出来,至少在我所见的范围内……?
    • 如果您不想使用内置设计器,还有其他方法可以生成实体;您可以在命令行上运行 SqlMetal.exe,也可以使用模板驱动的方法,例如 CodeSmith 模板 (www.plinqo.com) 或 Damien Guard 的 Linq2SQL 的 T4 模板。可扩展性的故事确实保持不变。
    • 投票推荐 sqlmetal。我总是忘记它的名字。当这么多其他工具的命名更具描述性时,为什么要命名应用程序 mage、sqlmetal 等?
    【解决方案2】:

    Linq2SQL 类是分部类,这意味着您可以通过添加自己的单独文件并在其中声明分部类的另一部分来轻松扩展它们。

    在该文件中,您可以根据需要自定义类 - 由于它是一个单独的文件,因此代码生成不会覆盖它。

    如果您查看例如AdventureWorks 数据库中的“Contact”类,Linq2SQL 将在 AdventureWorks.designer.cs 文件中生成:

    [Table(Name="Person.Contact")]
    public partial class Contact : INotifyPropertyChanging, INotifyPropertyChanged
    {
    

    现在您可以将“Contact.cs”文件添加到您的项目中,并扩展该部分类,例如通过引入一个新属性“DisplayName”:

    public partial class Contact 
    {
           public string DisplayName
           {  
              get { return string.Format("{0} {1}", FirstName, LastName); }
           }
        }
    

    在编译时,类的这两个部分合并在一起。

    另一部分是部分方法 - 可供您实现的方法,但如果它们没有实现,编译器会优化对它们的调用。

    对于 Linq2SQL 中的每个对象类,正在创建大量的部分方法(.NET 3.0 中的一项新功能) - 由您来实现!

    partial void InsertContact(Contact instance);
    partial void UpdateContact(Contact instance);
    partial void DeleteContact(Contact instance);
    
    partial void OnLoaded();
    partial void OnValidate(System.Data.Linq.ChangeAction action);
    partial void OnCreated();
    
    partial void OnFirstNameChanging(string value);
    partial void OnFirstNameChanged();
    
    partial void OnLastNameChanging(string value);
    partial void OnLastNameChanged();
    

    大量的扩展点!

    马克

    【讨论】:

    • 是的,抱歉,我了解部分类的概念以及它们的工作原理。我的问题是您如何自定义属性。您不能在部分文件中定义与自动生成的属性同名的属性 - 所以问题仍然存在,您如何自定义 Linq2SQL 实体中的属性?在您的示例中,如果 DisplayName 是数据库中的一列,我无法看到自定义该属性内的封装行为...
    • @Malcolm:不,不能“覆盖”或调整现有属性。在这种情况下,您可能应该考虑使用基于模板的方法来创建您的 Linq 对象,并调整模板以使属性虚拟化,以便您可以在派生类中覆盖它们。
    • 啊,好的,谢谢,您是否有任何像样的链接以更高级的方式使用 L2S?例如模板?
    • 但是,您可以将字段的“访问”设置为“私有”,然后创建自己的属性来包装它。即将 DisplayName 设置为私有并创建一个包含私有 DisplayName 的公共属性“DispName”。
    • @Jacob - 是的,你可以这样做 - 不是很漂亮,真的有点小技巧。 REAL 解决方案是将生成的 LINQ-2-SQL 类中的属性设为虚拟,以便可以覆盖它们
    【解决方案3】:

    由于 Linq2Sql 实体不是密封的,您可以从 Linq2Sql 类派生并在派生类中进行更改。

    在我的项目中,我不会对 Linq2Sql 类进行任何更改。相反,我建立了自己的一套 POCO,我可以根据自己的需要进行定制。然后我使用 Linq2Sql 仅使用存储库模式填充/持久化我的 POCO。

    Rob Connery 在他的博客 ASP.NET MVC Storefront 上有一个很棒的网络广播系列。在第一个网络广播中,他介绍了使用 Linq2Sql 作为存储库与 POCO 的结合

    【讨论】:

      【解决方案4】:

      看看这个:

      它比 sqlmetal(设计者用来生成代码)要好得多

      http://plinqo.com/default.aspx?AspxAutoDetectCookieSupport=1

      虽然需要 Codesmith 许可证,但恕我直言非常值得。

      【讨论】:

        【解决方案5】:

        如果没有一些严重的黑客攻击,就不可能修改未标记为虚拟的类的 get/set 属性中的逻辑(查看模拟框架以获取如何绕过这些限制的示例)。这就是将某些东西标记为虚拟的全部意义所在,以牺牲虚拟调用和性能损失为代价使其成为可消耗品。

        元数据类型标签,但是,将允许您使用无法修改的属性注释现有类:

        注意:盗自this related question

        [MetadataType (typeof (BookingMetadata))]
        public partial class Booking
        {
         // This is your custom partial class     
        }
        
        public class BookingMetadata
        {
         [Required] [StringLength(15)]
         public object ClientName { get; set; }
        
         [Range(1, 20)]
         public object NumberOfGuests { get; set; }
        
         [Required] [DataType(DataType.Date)]
         public object ArrivalDate { get; set; }
        }
        

        【讨论】:

          猜你喜欢
          • 2021-06-08
          • 1970-01-01
          • 1970-01-01
          • 2010-10-01
          • 2020-01-15
          • 2012-11-12
          • 1970-01-01
          • 1970-01-01
          • 2012-05-05
          相关资源
          最近更新 更多