如何将我的属性添加到代码生成的Linq2Sql类属性?

我想为Linq 2 Sql类属性添加属性。 例如,此列可以在用户界面中浏览,也可以在UI中自读,目前为止。

我考虑过使用模板,有谁知道如何使用它? 还是别的什么?

一般来说,您是否会使用代码生成的类来解决这个问题?

根据要求,这是一种使用CustomTypeDescriptor在运行时编辑属性的方法; 这里的示例是win-forms,但将它交换到WPF以查看它是否有效应该非常简单…

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Forms; // example POCO class Foo { static Foo() { // initializes the custom provider (the attribute-based approach doesn't allow // access to the original provider) TypeDescriptionProvider basic = TypeDescriptor.GetProvider(typeof(Foo)); FooTypeDescriptionProvider custom = new FooTypeDescriptionProvider(basic); TypeDescriptor.AddProvider(custom, typeof(Foo)); } public string Name { get; set; } public DateTime DateOfBirth { get; set; } } // example form static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.Run( new Form { Controls = { new DataGridView { Dock = DockStyle.Fill, DataSource = new BindingList { new Foo { Name = "Fred", DateOfBirth = DateTime.Today.AddYears(-20) } } } } }); } } class FooTypeDescriptionProvider : TypeDescriptionProvider { ICustomTypeDescriptor descriptor; public FooTypeDescriptionProvider(TypeDescriptionProvider parent) : base(parent) { } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { // swap regular descriptor for bespoke (Foo) descriptor if (descriptor == null) { ICustomTypeDescriptor desc = base.GetTypeDescriptor(typeof(Foo), null); descriptor = new FooTypeDescriptor(desc); } return descriptor; } } class FooTypeDescriptor : CustomTypeDescriptor { internal FooTypeDescriptor(ICustomTypeDescriptor parent) : base(parent) { } public override PropertyDescriptorCollection GetProperties() { // wrap the properties return Wrap(base.GetProperties()); } public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { // wrap the properties return Wrap(base.GetProperties(attributes)); } static PropertyDescriptorCollection Wrap(PropertyDescriptorCollection properties) { // here's where we have an opportunity to swap/add/remove properties // at runtime; we'll swap them for pass-thru properties with // edited atttibutes List list = new List(properties.Count); foreach (PropertyDescriptor prop in properties) { // add custom attributes here... string displayName = prop.DisplayName; if (string.IsNullOrEmpty(displayName)) displayName = prop.Name; list.Add(new ChainedPropertyDescriptor(prop, new DisplayNameAttribute("Foo:" + displayName))); } return new PropertyDescriptorCollection(list.ToArray(), true); } } class ChainedPropertyDescriptor : PropertyDescriptor { // this passes all requests through to the underlying (parent) // descriptor, but has custom attributes etc; // we could also override properties here... private readonly PropertyDescriptor parent; public ChainedPropertyDescriptor(PropertyDescriptor parent, params Attribute[] attributes) : base(parent, attributes) { this.parent = parent; } public override bool ShouldSerializeValue(object component) { return parent.ShouldSerializeValue(component); } public override void SetValue(object component, object value) { parent.SetValue(component, value); } public override object GetValue(object component) { return parent.GetValue(component); } public override void ResetValue(object component) { parent.ResetValue(component); } public override Type PropertyType {get { return parent.PropertyType; } } public override bool IsReadOnly { get { return parent.IsReadOnly; } } public override bool CanResetValue(object component) {return parent.CanResetValue(component);} public override Type ComponentType { get { return parent.ComponentType; } } public override void AddValueChanged(object component, EventHandler handler) {parent.AddValueChanged(component, handler); } public override void RemoveValueChanged(object component, EventHandler handler) { parent.RemoveValueChanged(component, handler); } public override bool SupportsChangeEvents { get { return parent.SupportsChangeEvents; } } } 

您可以利用System.ComponentModel.DataAnnotations中的新元数据function,这将允许我们将MetaData与现有域模型分开。

例如:

 [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; } } 

你可能想考虑使用Damien Guard的T4模板来实现Linq To Sql 。 修改他的模板很可能会给你你想要的结果。

希望这可以帮助!

这是代码生成的常见问题; 虽然您可以通过其他分部类添加成员和级别属性,但您无法向生成的成员添加属性。 为了补偿,一些基于属性的机制允许您指定类中的属性(命名成员),但不能指定您引用的任何属性。

一个硬核选项是编写一个TypeDescriptionProvider ,为属性提供自定义PropertyDescriptor定义。 这将允许您完全控制UI绑定工具(如PropertyGridDataGridView等)使用的元数据。

但是,如果您也可以手动设置它们,那么设置一些UI属性可能太多了! 但是如果你对追求这个选项感兴趣,请告诉我 – 这对我来说是一个熟悉的领域,但如果你不想要它,那么编写一个例子的代码太多了。

注意:如果您正在使用PropertyGrid ,那么您不能手动设置属性,但您可以编写TypeConverter ,这比完整的TypeDescriptionProvider少一点工作; 只是从ExpandableObjectConverterinheritance并覆盖GetProperties() 。 你仍然需要一个垫片PropertyDescriptor ,所以仍然不是微不足道的……

您可以使用partial类来使您的实体实现一个接口,该接口声明实体的相同属性,然后将属性放在接口上。

这样,您可以使用接口类型从属性中获取属性。

我不知道你是否能够以这种方式使用这些属性,但你可以尝试这样的东西。

例:

 public interface IConcept { long Code { get; set; } [Unique] string Name { get; set; } bool IsDefault { get; set; } } public partial class Concept : IConcept { } [Table(Name="dbo.Concepts")] public partial class Concept { //... } 

您还可以编写/使用其他代码生成器来代替默认的MSLinqToSQLGenerator。

一个选择就是这个 。

根据我的需要,我建立了自己的。 我不知道是否有办法使用DBML Designer或xml文件指示必须在每个属性中放置哪些属性,但也许您可以找到一种方法来使用此替代方法来帮助您解决问题。