我应该如何使用Entity Framework建模静态参考数据?

时间:2018-02-05 19:26:23

标签: c# entity-framework oop design-patterns data-modeling

我有一个模拟模型,它使用数据库来存储输入和输出数据,使用Entity Framework和Database First方法。通过数据访问层或多或少地查询数据库,如下所述:https://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/

但是,使用的一些静态输入数据存储在数据库中,而是作为字段硬编码到应用程序中。此数据是真正静态的,在应用程序运行时不会更改。例如:

public class Currency
{
    public string Symbol { get; private set; }
    public string Name { get; private set; }

    private Currency()
    {
    }

    // Fields like this store reference data
    public static readonly Currency USD = new Currency
    {
        Symbol = "USD",
        Name = "US Dollar"
    };

    public static readonly Currency EUR = new Currency
    {
        Symbol = "EUR",
        Name = "Euro"
    };
}

这具有以下优点:参考参考数据就像使用例如参考数据一样容易。整个模型中Currency.USD,无需通过数据访问层。如何实现这一点的缺点是数据模型是笨拙的而不是真正的关系(在关系是通过外键强制执行的意义上);使用上述参考数据的模型对象,例如

public class Transaction
{
    public int Id { get; set; }
    public Currency Currency { get; set; }
    public double Price { get; set; }
}

在数据库中有一个支持表,如下所示:

create table Transaction
(
    Id int not null primary key,
    Currency nvarchar(3) not null , -- Currency symbol, not a foreign key
    Price float not null 
);

在通过业务层读取和写入时,货币属性在字符串和对象之间来回转换。

我想用以下目标重写:

  • 将数据库中的静态参考数据与所有其他数据一起存储,以保持数据模型的清洁。
  • 每次需要静态参考数据时(即尽可能接近硬编码Currency.USD),不必查询数据访问层。在整个模拟运行过程中,参考数据可能在启动时读取一次,然后查询1,000,000,000次。

我在寻找某种缓存机制吗?这可能足够高效吗?一般来说,解决这个问题的优雅方法是什么?特别是实体框架?

感谢。

1 个答案:

答案 0 :(得分:1)

以下是关于使用EF执行此操作的模式的想法:

此示例中的静态参考数据"颜色"同时具有非int键和额外属性。你不能用Enum做这两件事。它使用初始化程序将参考数据添加到数据库,但在数据库中,您只需提前添加它,并假设它在那里。

此模式的变体将使用在启动时从数据库检索的参考实体的惰性静态集合,而不是在类定义中对值进行硬编码。在任何一种情况下,在SaveChanges中将引用实体标记为Unchanged都会阻止EF尝试将它们插入数据库。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;

namespace Ef6Test
{

    public class Color
    {
        public static Color Red = new Color() { Name = "Red", RGB = 0xFF0000 };
        public static Color Green = new Color() { Name = "Green", RGB = 0x00FF00 };
        public static Color Blue = new Color() { Name = "Blue", RGB = 0x0000FF };
        [Key]
        public string Name { get; set; }
        public int RGB { get; set; }
    }

    public class Car
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public string ColorName { get; set; }
        public Color Color { get; set; }
    }

    class Db : DbContext
    {

        public DbSet<Color> Colors { get; set; }
        public DbSet<Car> Cars { get; set; }


        public override int SaveChanges()
        {
            return SaveChanges(false);
        }
        public int SaveChanges(bool includeStatic = false)
        {
            if (!includeStatic)
            {
                foreach (var e in ChangeTracker.Entries<Color>())
                {
                    e.State = EntityState.Unchanged;
                }
            }

            return base.SaveChanges();
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

    class MyInitializer : DropCreateDatabaseAlways<Db>
    {
        protected override void Seed(Db context)
        {
            base.Seed(context);
            context.Colors.AddRange(new[] {Color.Red,Color.Green,Color.Blue });
            context.SaveChanges(true);

        }
    }

    class Program
    {    
        static void Main(string[] args)
        {    
            Database.SetInitializer(new MyInitializer());

            using (var db = new Db())
            {
                db.Database.Log = m => Console.WriteLine(m);
                db.Database.Initialize(true);
            }
            using (var db = new Db())
            {
                db.Database.Log = m => Console.WriteLine(m);

                var c = db.Cars.Create();
                c.Color = Color.Red;
                db.Cars.Add(c);

                db.SaveChanges();

            }


            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();
        }
    }
}