【问题标题】:Shortcut in Fluent API to set multiple properties as requiredFluent API 中用于根据需要设置多个属性的快捷方式
【发布时间】:2013-08-25 01:46:12
【问题描述】:
  1. 这是我目前正在做的事情:

    modelBuilder.Entity<Product>().Property(e => e.Name).IsRequired();                   
    modelBuilder.Entity<Product>().Property(e => e.UPC).IsRequired();      
    modelBuilder.Entity<Product>().Property(e => e.Price).IsRequired();      
    modelBuilder.Entity<Product>().Property(e => e.Description).IsRequired();
    
  2. 这是我想做的事情:

    modelBuilder.Entity<Product>()
        .Property(e => e.Name).IsRequired()
        .Property(e => e.UPC).IsRequired()
        .Property(e => e.Price).IsRequired()
        .Property(e => e.Description).IsRequired()
    

不过,后者不起作用。有没有其他方法不必每次都重复modelBuilder.Entity&lt;Product&gt;()

  1. 这是当前最简洁的选项:

    var e = modelBuilder.Entity<Product>();
    e.Property(e => e.Name).IsRequired();                   
    e.Property(e => e.UPC).IsRequired();      
    e.Property(e => e.Price).IsRequired();      
    e.Property(e => e.Description).IsRequired();
    

【问题讨论】:

  • 我不知道。您的第一个示例是 AFAIK 的唯一方法
  • 我知道使用 fluent API 进行链接有一些限制,但不记得它们到底是什么。查看此文档,我看不到任何将 .Property 用于一个实体 msdn.microsoft.com/en-gb/data/jj591617 的示例
  • resharper templates 想到

标签: c# entity-framework fluent-interface


【解决方案1】:

这与所有现有的 DbModelBuilder 扩展方法兼容,因为它只是在顶部添加了一个流畅的层,但它确实带来了一些语法开销。不完全符合您的要求,但不涉及使用支持代码。尚未对此进行全面测试,但如果您对语法感到满意,它应该可以工作:

// First option - like this better because it has less cruft than multiple Has invocations

var modelBuilder = new DbModelBuilder();
var modelConfiguration = new ModelConfigurator(modelBuilder);

modelConfiguration.Entity<Product>().Has(e => {
                                         e.Property(en => en.Name).IsRequired();
                                         e.Property(en => en.UPC).IsRequired();
                                         e.Property(en => en.Price).IsRequired();
                                         e.Property(en => en.Description).IsRequired();}
                                        );           

var modelBuilder = new DbModelBuilder();
var modelConfiguration = new ModelConfigurator(modelBuilder);
modelConfiguration.Entity<Product>().Has(e => e.Property(en => en.Name).IsRequired())
                                    .Has(e => e.Property(en => en.UPC).IsRequired())
                                    .Has(e => e.Property(en => en.Price).IsRequired())
                                    .Has(e => e.Property(en => en.Description).IsRequired());

// continue configuring properties, and creating methods on ModelConfigurator as needed

支持代码:

  public class Product{
        public string Name {get;set;}
        public double Price {get;set;}
        public string UPC {get;set;}
        public string Description {get;set;}

    }

    public class ModelConfigurator{

        public DbModelBuilder ModelBuilder{get;set;}

        public ModelConfigurator(DbModelBuilder modelBuilder){
            ModelBuilder = modelBuilder;
        }

        public EntityConfigurator<TEntity> Entity<TEntity>() where TEntity : class {
            var entity = ModelBuilder.Entity<TEntity>();
            return new EntityConfigurator<TEntity>(entity);
        }
    }

    public class EntityConfigurator<TEntity> where TEntity : class{

        public EntityTypeConfiguration<TEntity> EntityTypeConfiguration {get;set;}

        public EntityConfigurator(EntityTypeConfiguration<TEntity> entityTypeConfiguration){
            EntityTypeConfiguration = entityTypeConfiguration;
        }

        public EntityConfigurator<TEntity> Has(Action<EntityTypeConfiguration<TEntity>> a){
            a(this.EntityTypeConfiguration);
            return this;
        }
    }

【讨论】:

  • 那行得通,所以我把它标记为答案。不过,由于它的语法开销,我可能会继续使用标准的 Fluent API,因为我最初问题中的第三个选项很容易让其他开发人员理解,同时也相当简洁。
  • 我认为这是最有意义的,除非您想花大量时间通过覆盖大量内部结构来重做现有的流畅界面。
【解决方案2】:

另一种选择,在 Entity() 之上不需要 Has():

modelConfiguration.Entity<Product>(e => {
                                   e.Property(en => en.Name).IsRequired();
                                   e.Property(en => en.UPC).IsRequired();
                                   e.Property(en => en.Price).IsRequired();
                                   e.Property(en => en.Description).IsRequired();}
                                  );

扩展方法:

public static EntityTypeConfiguration<TEntity> Entity<TEntity>(this DbModelBuilder modelBuilder, Action<EntityTypeConfiguration<TEntity>> action) where TEntity : class
{
    var r = modelBuilder.Entity<TEntity>();
    action(r);
    return r;
}

【讨论】:

    【解决方案3】:

    我想您可以执行以下操作,尽管我认为这很尴尬。

    public static class EntityConfigExtensions
    {
        public static EntityTypeConfiguration<TEntity> Prop<TEntity, TProp>(this EntityTypeConfiguration<TEntity> self, Expression<Func<TEntity, TProp>> propExpression) where TEntity : class
        {
            self.Property(propExpression);
            return self;
        }
        public static EntityTypeConfiguration<TEntity> RequiredProp<TEntity, TProp>(this EntityTypeConfiguration<TEntity> self, Expression<Func<TEntity, TProp>> propExpression) where TEntity : class
        {
            self.Property(propExpression).IsRequired();
            return self;
        }
        // etcetera for other frequently used configs
        // ...
        // And, borrowing from David: a catch-all for the rest
        public static EntityTypeConfiguration<TEntity> Configure<TEntity, TProp>(this EntityTypeConfiguration<TEntity> self, Action<EntityTypeConfiguration<TEntity>> configAction) where TEntity : class
        {
            configAction(self);
            return self;
        }
    }
    

    用法:

    modelBuilder.Entity<Product>()
        .Prop(e => e.Name)
        .RequiredProp(e => e.UPC)
        .RequiredProp(e => e.Price)
        .Configure(x => x.Ignore(e => e.Description));
    

    【讨论】:

    • 我收到错误消息,“'new()' 约束不能与 'struct' 约束一起使用。”
    • 你说得对,需要删除。有趣,因为 MSDN 文档状态: public PrimitivePropertyConfiguration Property( Expression> propertyExpression ) where T : struct, new()
    • @ShaunLuttin 如果 MSDN 文档不正确,您可能还想尝试不使用 where TProp : struct 约束。
    • 我现在收到以下错误:类型“TEntity”必须是引用类型才能在泛型类型或方法中用作参数“TEntityType”。
    • @ShaunLuttin 是的,正如我在之前的评论中指出的那样,您可能还想删除where TProp: struct 约束并添加where TEntity : class。 MSDN 文档 (msdn.microsoft.com/en-us/library/gg671207(v=vs.103).aspx) 似乎不正确。我已经编辑了答案
    【解决方案4】:

    我为 EF Core 改编了 jnm2's answer

    public static class ModelBuilderExtensions
    {
        public static EntityTypeBuilder<T> Entity<T>(
            this ModelBuilder modelBuilder,
            Action<EntityTypeBuilder<T>> action) where T : class
        {
            var e = modelBuilder.Entity<T>();
            action(e);
            return e;
        }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>(b =>
        {
            b.Property(e => e.Name).IsRequired();
            b.Property(e => e.UPC).IsRequired();
            b.Property(e => e.Price).IsRequired();
            b.Property(e => e.Description).IsRequired();}
        });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-18
      • 2017-03-25
      • 1970-01-01
      相关资源
      最近更新 更多