简体   繁体   English

引用应用程序的实体框架上下文的C#类库?

[英]C# class library that references the application's Entity Framework context?

I am making a class library that uses its own database table that will be generated with CodeFirst. 我正在制作一个使用自己的数据库表的类库,该数据库表将通过CodeFirst生成。 The class library defines the model, and needs a DbContext to add records to it. 类库定义模型,并且需要DbContext向其添加记录。 But how do I do that, without having knowledge of the applications own db context at compile time? 但是,在不知道应用程序在编译时拥有数据库上下文的情况下,该如何做呢?

The application needs to add this line to his own db context: 应用程序需要将此行添加到他自己的数据库上下文中:

public DbSet<MyClassLibraryRecords> MyClassLibraryRecords { get; set; }

but then he needs to somehow give the application db context to the class library so I can access MyClassLibraryRecords to do app_context.MyClassLibraryRecords.Add(record); 但是随后他需要以某种方式将应用程序数据库上下文提供给类库,以便我可以访问MyClassLibraryRecords来执行app_context.MyClassLibraryRecords.Add(record); ?

Do I have to use a callback method for that, or a method the application will override to do the actual storing in database? 我是否必须为此使用回调方法,或者应用程序将覆盖该方法以实际存储在数据库中? I'd rather not, it would be easier if I could do it all in the class library... 我宁愿不这样做,如果我可以在类库中完成所有操作,那会更容易...

you need to build your own DBContext, so that entity framework is aware of the classes that's part of your domain. 您需要构建自己的DBContext,以便实体框架知道属于您域的类。

    CREATE TABLE [dbo].[account](
        [account_id] [int] IDENTITY(1,1) NOT NULL,
        [name] [nvarchar](50) NOT NULL,
     CONSTRAINT [PK_dbo.account] PRIMARY KEY CLUSTERED 
    (
        [account_id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO 


    CREATE TABLE [dbo].[address](
        [address_id] [int] IDENTITY(1,1) NOT NULL,
        [account_id] [int] NOT NULL,
        [full_address] [nvarchar](256) NOT NULL,
     CONSTRAINT [PK_dbo.address] PRIMARY KEY CLUSTERED 
    (
        [address_id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

    ALTER TABLE [dbo].[address]  WITH CHECK ADD  CONSTRAINT [FK_dbo.address_dbo.account_account_id] FOREIGN KEY([account_id])
    REFERENCES [dbo].[account] ([account_id])

-------------------------------------------------------

db connection string
  <add name="accountDB" connectionString="data source=.; initial catalog=test; integrated security=true;" providerName="System.Data.SqlClient" />

---------------------------------------------------


    using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;





/// <summary>
/// Define my domain. 
/// </summary> 
public class Account
{
    public Account()
    {
        this.Addresses = new List<Address>();
    }
    public int? AccountID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}
public class Address
{
    public int? AddressID { get; set; }
    public int AccountID { get; set; }
    public string FullAddress { get; set; }
}
public interface IAccountService
{
    Account GetAccount(int accountID);
    void SaveAccount(Account account);
}
public interface IAccountRepository
{
    IQueryable<Account> GetAccounts();
    void UpdateAccount(Account account);
    void CreateAccount(Account account);
}
public class AccountService : IAccountService
{
    private IAccountRepository _repository;
    public AccountService(IAccountRepository repository)
    {
        this._repository = repository;
    }
    public Account GetAccount(int accountID)
    {
        //you can do some validation. for ex) if we pass the user's name, we can see if they have access rights to the system,  module, and data 
        return (from acc in this._repository.GetAccounts().AsNoTracking()
                where acc.AccountID == accountID
                select acc).FirstOrDefault();
    }
    public void SaveAccount(Account account)
    {
        //apply your business rules such as validating the data, user access rights, and etc
        if (account.AccountID.HasValue)
        {
            this._repository.UpdateAccount(account);
        }
        else
        {
            this._repository.CreateAccount(account);
        }
    }
}




/// <summary>
/// Data access layer.
/// 
/// This layer knows about your data saource such as sql server, oracle, or mongoDB.
/// </summary>  
public class AccountConfig : EntityTypeConfiguration<Account>
{
    public AccountConfig() : base()
    {
        this.ToTable("account", "dbo")
            .HasKey(p => p.AccountID);

        this.Property(p => p.AccountID)
            .HasColumnName("account_id")
            .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);

        this.Property(p => p.Name)
            .HasColumnName("name")
            .HasColumnType("nvarchar")
            .HasMaxLength(50)
            .IsRequired();

        //define the relationship between account and address
        this.HasMany(p => p.Addresses).WithRequired().HasForeignKey(p => p.AccountID).WillCascadeOnDelete(false);
    }
}
public class AddressConfig : EntityTypeConfiguration<Address>
{
    public AddressConfig() : base()
    {
        this.ToTable("address", "dbo")
            .HasKey(p => p.AddressID);

        this.Property(p => p.AddressID)
            .HasColumnName("address_id")
            .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);

        this.Property(p => p.AccountID)
            .HasColumnName("account_id")
            .IsRequired();

        this.Property(p => p.FullAddress)
            .HasColumnName("full_address")
            .HasColumnType("nvarchar")
            .HasMaxLength(256)
            .IsRequired();
    }
}
public class AccountDBContext : DbContext
{
    public AccountDBContext() : this("accountDB") { }
    public AccountDBContext(string nameOrConnectionString) : base(nameOrConnectionString)
    {
        //I dont want to use any database initialization i.e create database if it doesnt exist
        //since your dev shop will have a deployment process, get use to the process of generating deployment scripts. 
        Database.SetInitializer<AccountDBContext>(null);
        this.Configuration.ProxyCreationEnabled = false;
        this.Configuration.LazyLoadingEnabled = false;
    }

    public IDbSet<Account> Accounts { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //map the domain types to the database tables using your database naming convention.
        modelBuilder.Configurations.Add(new AddressConfig());
        modelBuilder.Configurations.Add(new AccountConfig());
    }
}

//repository is on the data access layer, because it's coupled to EF and the context object.
public class AccountRepository : IAccountRepository
{
    private AccountDBContext _context;
    public AccountRepository()
    {
        this._context = new AccountDBContext();
    }
    public AccountRepository(string nameOrConnectionString)
    {
        this._context = new AccountDBContext(nameOrConnectionString);
    }

    public IQueryable<Account> GetAccounts()
    {
        return this._context.Accounts
                        .AsNoTracking()
                        .Include("Addresses");
    }

    public void CreateAccount(Account account)
    {
        this._context.Entry(account).State = EntityState.Added;
        this._context.SaveChanges();
    }

    public void UpdateAccount(Account account)
    {
        var temp = (from acc in this.GetAccounts()
                    where acc.AccountID == account.AccountID
                    select acc).First();

        temp.Name = account.Name;

        //sync address... we'll just add for brevity sake.
        if (account.Addresses != null)
        {
            foreach (var addr in account.Addresses)
            {
                if (!addr.AddressID.HasValue)
                {
                    this._context.Entry(addr).State = EntityState.Added;
                }
            }
        }

        this._context.SaveChanges();
    }
}






public class Program
{
    public static void Main()
    {
        try
        {
            IAccountService service = new AccountService(new AccountRepository());

            //create new 
            var account = new Account()
            {
                Name = "john doe"
            };
            account.Addresses.Add(new Address()
            {
                FullAddress = "San Fran, CA"
            });
            account.Addresses.Add(new Address()
            {
                FullAddress = "Texas"
            });
            service.SaveAccount(account);





            //get the account. I know the first accountID is one. I checked the database for testing.
            ;
            var savedAccount = service.GetAccount(1);

            //lets update it
            savedAccount.Name = "J. Doe";
            savedAccount.Addresses.Add(new Address()
            {
                AccountID = savedAccount.AccountID.Value,
                FullAddress = "Conn"
            });

            service.SaveAccount(savedAccount);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

}

you really need to read up on entity framework. 您确实需要阅读实体框架。 we didn't even talk about topics such as transactions, concurrency, complex object graphs, and patterns. 我们甚至没有谈论诸如事务,并发,复杂对象图和模式之类的话题。

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

相关问题 类库中的实体框架,无需外部引用 - Entity Framework in Class Library without outside references 当实体框架模型在专用的类库中时,如何在C#应用程序中定义连接字符串和数据库提供程序? - How to define connection string and database provider in an C# application when the Entity Framework model is in a dedicated class library? 类库中的C#实体框架数据库迁移 - C# Entity Framework Database Migrations in Class Library C# 实体框架向来自外部库的实体添加新列 - C# Entity Framework Adding New Column to Entity that's from external library C#实体框架跟踪实体上的脏内容尚未添加到上下文 - c# entity framework track dirty on entity not added to context yet .NET核心实体框架 - 在类库中为Context添加迁移 - .NET Core Entity Framework - Add migration for Context in class library 各种应用程序使用的实体框架类库中的上下文实例化 - context instancing in entity framework class library used by different kinds of applications 实体框架上下文工厂和循环引用 - Entity Framework Context Factory And Cyclic References 类库中的实体框架7 - Entity Framework 7 in Class Library 实体框架的C#数据库抽象类 - C# database abstraction class with Entity Framework
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM