Подтвердить что ты не робот

Как я могу добавить свои атрибуты в свойства классов Linq2Sql с кодовым генератором?

Я хотел бы добавить атрибуты в свойства классов Linq 2 Sql. Например, этот столбец можно просматривать в пользовательском интерфейсе или ReadOnly в пользовательском интерфейсе и до сих пор.

Я думал об использовании шаблонов, кто-нибудь знает, как его использовать? или что-то другое?

Вообще говоря, вы бы сделали, чтобы решить эту проблему, когда классы генерируются кодом?

4b9b3361

Ответ 1

В соответствии с запросом здесь используется подход с использованием CustomTypeDescriptor для редактирования атрибутов во время выполнения; пример здесь - это win-формы, но довольно просто поменять его в 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 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; } }
}

Ответ 2

Вы можете воспользоваться новой функциональностью метаданных в System.ComponentModel.DataAnnotations, которая позволит нам отделить 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; }
}

Ответ 3

Возможно, вам захочется использовать шаблоны Damien Guard T4 для Linq To Sql. Изменение его шаблонов, скорее всего, даст вам результаты, которые вы ищете.

Надеюсь, это поможет!

Ответ 4

Это обычная проблема с генерацией кода; в то время как вы можете добавлять элементы и атрибуты уровня класса через дополнительный частичный класс, вы не можете добавлять атрибуты к сгенерированным членам. Чтобы компенсировать, некоторые механизмы, основанные на атрибутах, позволяют вам указывать атрибуты в классе (имена членов), но не любые из них, которые вы цитируете.

Один вариант хардкора - написать TypeDescriptionProvider, который предоставляет пользовательские определения PropertyDescriptor для свойств. Это позволит вам полностью контролировать метаданные, используемые инструментами привязки UI, такими как PropertyGrid, DataGridView и т.д.

Однако, возможно, это слишком большая работа, просто чтобы установить несколько UI propertiex, если вы также можете установить их вручную! Но если вы заинтересованы в том, чтобы преследовать этот вариант, дайте мне знать - это знакомая область для меня, но слишком много кода, чтобы написать пример, если вы этого не хотите.

Примечание: если вы используете PropertyGrid, то вы не можете установить свойства вручную, но вы можете написать TypeConverter, что немного меньше работы, чем полный TypeDescriptionProvider; просто наследуем от ExpandableObjectConverter и переопределяем GetProperties(). Вам все равно потребуется прокладка PropertyDescriptor, поэтому все еще не тривиально...

Ответ 5

Вы можете использовать частичный класс, чтобы ваша сущность реализовала интерфейс, который объявляет те же свойства вашего объекта, а затем помещает атрибуты в интерфейс.

Таким образом вы можете использовать тип интерфейса для получения атрибутов из свойств.

Я не знаю, сможете ли вы использовать атрибуты таким образом, но вы можете попробовать что-то подобное.

Пример:


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

Ответ 6

Вы также можете написать/использовать другой генератор кода вместо стандартного MSLinqToSQLGenerator.

Один из вариантов для запуска - этот.

Я построил свои собственные, в соответствии с моими потребностями. Я не знаю, есть ли способ указать, какие атрибуты должны быть помещены в каждое свойство, используя DBML Designer или XML файл, но, возможно, вы можете найти способ использовать эту альтернативу, чтобы помочь вам в решении вашей проблемы.