2016-04-26 34 views
0

我正在制作一个使用自己的数据库表的类库,该表将与CodeFirst一起生成。类库定义了模型,并且需要DbContext向其添加记录。但是如何在编译时不知道应用程序自己的数据库上下文的情况下做到这一点?引用应用程序的实体框架上下文的C#类库?

应用程序需要此行添加到自己的数据库方面:

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

但他需要以某种方式给应用程序数据库方面的类库,所以我可以访问MyClassLibraryRecordsapp_context.MyClassLibraryRecords.Add(record);

我是否必须使用回调方法,或者应用程序将覆盖的方法来执行数据库中的实际存储?我宁愿不,如果我可以在类库中做到这一点,会更容易...

回答

2

您需要构建自己的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); 
     } 
    } 

} 

你真的需要阅读实体框架。我们甚至没有谈论诸如事务,并发性,复杂对象图和模式等主题。

+0

好的,然后应用程序需要从AccountContext继承? – CodeOrElse

+0

来自实体框架的Dbcontext – dfdsfdsfsdf

+0

我更新了代码。它应该工作,并不意味着完整,尤其是数据访问代码。我设计了Account来包含Address对象,所以你可以通过头痛来持久化一个断开的对象图。试试看,并做大量的阅读。 – dfdsfdsfsdf