简体   繁体   English

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

[英]How can I add my attributes to Code-Generated Linq2Sql classes properties?

I would like to add attributes to Linq 2 Sql classes properties. 我想为Linq 2 Sql类属性添加属性。 Such as this Column is browsable in the UI or ReadOnly in the UI and so far. 例如,此列可以在UI中使用,也可以在UI中的ReadOnly中使用,目前为止。

I've thought about using templates, anybody knows how to use it? 我考虑过使用模板,有谁知道如何使用它? or something different? 还是别的什么?

Generally speaking, would do you do to address this issue with classes being code-generated? 一般来说,您是否会使用代码生成的类来解决这个问题?

You can take advantage of the new Metadata functionality in the System.ComponentModel.DataAnnotations which will allow us to separate the MetaData from the existing domain model. 您可以利用System.ComponentModel.DataAnnotations中的新元数据功能,这将允许我们将MetaData与现有域模型分开。

For example: 例如:

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

As requested, here's an approach using a CustomTypeDescriptor to edit the attributes at run-time; 根据要求,这是一种使用CustomTypeDescriptor在运行时编辑属性的方法; the example here is win-forms, but it should be pretty simple to swap it into WPF to see if it works... 这里的例子是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<Foo> {
                            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<PropertyDescriptor> list = new List<PropertyDescriptor>(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; } }
}

You may want to consider using Damien Guard's T4 templates for Linq To Sql . 你可能想考虑使用Damien Guard的T4模板来实现Linq To Sql Modifying his templates would most likely give you the results you seek. 修改他的模板很可能会给你你想要的结果。

Hope this helps! 希望这可以帮助!

This is a common problem with code-generation; 这是代码生成的常见问题; while you can add members and class level attributes via an additional partial class, you can't add attributes to the generated members. 虽然您可以通过其他分部类添加成员和级别属性,但您无法向生成的成员添加属性。 To compensate, some attribute-based mechanisms allow you to specify the attributes at the class (naming the member), but not any of the ones you cite. 为了补偿,一些基于属性的机制允许您指定类中的属性(命名成员),但不能指定您引用的任何属性。

One hardcore option would be to write a TypeDescriptionProvider that supplies custom PropertyDescriptor definitions for the properties. 一个硬核选项是编写一个TypeDescriptionProvider ,为属性提供自定义PropertyDescriptor定义。 This would allow you to fully control the metadata used by UI binding tools like PropertyGrid , DataGridView , etc. 这将允许您完全控制UI绑定工具(如PropertyGridDataGridView等)使用的元数据。

However, this is possibly too much work simply to set a few UI propertiex if you can also set them by hand! 但是,如果您也可以手动设置它们,那么设置一些UI属性可能太多了! But if you are interested in pursuing that option, let me know - it is a familiar area to me, but too much code to write an example if you don't want it. 但是,如果你有兴趣追求这个选项,请告诉我 - 这对我来说是一个熟悉的领域,但如果你不想要它,那么编写一个例子的代码太多了。

Note: if you are using PropertyGrid , then you can't set the properties by hand, but you can write a TypeConverter , which is a bit less work than a full TypeDescriptionProvider ; 注意:如果您正在使用PropertyGrid ,那么您不能手动设置属性,但您可以编写TypeConverter ,这比完整的TypeDescriptionProvider少一些; just inherit from ExpandableObjectConverter and override GetProperties() . 只是从ExpandableObjectConverter继承并覆盖GetProperties() You'll still need a shim PropertyDescriptor , so still not trivial... 你仍然需要一个垫片PropertyDescriptor ,所以仍然不是微不足道的......

You can use a partial class to make your entity implement a interface that declares the same properties of your entity and then put the attributes on the interface. 您可以使用分部类使您的实体实现一个接口,该接口声明实体的相同属性,然后将属性放在接口上。

This way you can use the interface type to get the attributes from the properties. 这样,您可以使用接口类型从属性中获取属性。

I don't know if you will be able to use the attributes this way, but you can try something like that. 我不知道你是否能够以这种方式使用属性,但你可以尝试这样的东西。

Example: 例:


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
{
//...
}

You can also write/use another code generator in place of the default MSLinqToSQLGenerator. 您还可以编写/使用其他代码生成器来代替默认的MSLinqToSQLGenerator。

One option to start from is this one . 一个选择就是这一个

I built my own, according to my needs. 根据我的需要,我建立了自己的。 I don't know if there is a way to indicate which attributes must be placed in each property using the DBML Designer, or xml file, but maybe you can find a way to use this alternative to help you with your problem. 我不知道是否有办法使用DBML Designer或xml文件指示必须在每个属性中放置哪些属性,但也许您可以找到一种方法来使用此替代方法来帮助您解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM