如何告诉 EF / DbSet 附加到 SQL 视图而不是尝试创建同名的表?
我想使用 Code-First 的 DropCreateDatabaseAlways
和 DropCreateDatabaseIfModelChanges
功能,因为我围绕该功能构建了许多集成测试。有没有比创建表、删除表,然后使用 sql 命令创建视图更优雅的方式附加到 SQL 视图?
[使用 VS2010 Professional、ASP.NET 4、MVC3、EF4、SQL Server 2008 R2 Express、Win7]
public MyContext : DbContext {
public DbSet<Person> Persons {get; set;}
public DbSet<Worker> Workers {get; set;}
public DbSet<Signin> Signins {get; set;}
public DbSet<SigninView> SigninView {get; set;}
}
public class Person
{
public int ID { get; set; }
public virtual Worker Worker { get; set; }
}
public class Worker
{
public int ID { get; set; }
public int barcodenumber {get; set;}
public virtual Person Person { get; set; }
public virtual ICollection<WorkerSignin> workersignins { get; set; }
}
public class WorkerSignin
{
public int ID { get; set; }
public virtual Worker worker {get; set;}
public int barcodenumber {get; set;}
}
Person.ID == Worker.ID。它们是 1 到 0..1 的关系。总会有一个人;可能没有工人记录。
public class PersonBuilder : EntityTypeConfiguration<Person>
{
public PersonBuilder()
{
ToTable("Persons");
HasKey(k => k.ID);
HasOptional(p => p.Worker).WithRequired().WillCascadeOnDelete();
}
}
public class WorkerBuilder : EntityTypeConfiguration<Worker>
{
public WorkerBuilder()
{
HasKey(k => k.ID);
HasMany(s => s.workersignins)
.WithOptional(s => s.worker)
.HasForeignKey(s => s.WorkerID);
}
}
登录表接收来自条形码扫描仪的输入。工作人员刷卡并登记当天。 客户端要求记录登录,即使扫描时 Worker 表中没有相应的记录。由于客户端的要求,我计划使用一个我可以控制的 ID主键,并以编程方式或尽可能与视图关联条形码编号。
SigninView 结合了 Person、Worker 和 Signin 表中的信息,以显示在刷 ID 的网页上。我假设 SQL Server 视图比关联 3 个表数据的 C# 视图更快。 (我觉得我没有时间停下来测试这个)。
所以...我想做的是附加到视图。我可以使用 DbSet<> 附加到视图,但在开发应用程序时,我还使用 CodeFirst 重新创建表结构。
现在我遇到了一个问题,Code-First 创建了一个表 SigninView,然后删除它并使用 SqlCommands 创建视图:
public class MyInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext myDB)
{
myDB.Database.SqlCommand(@"drop table machete.dbo.WorkerSigninView");
myDB.Database.SqlCommand(@"CREATE VIEW [dbo].[WorkerSigninView]
AS
SELECT dbo.WorkerSignins.ID, dbo.WorkerSignins.barcodenumber
FROM dbo.Persons INNER JOIN
dbo.Workers ON dbo.Persons.ID = dbo.Workers.ID RIGHT OUTER JOIN
dbo.WorkerSignins ON dbo.Workers.barcodenumber = dbo.WorkerSignins.barcodenumber");
}
I would like to to use Code-First's DropCreateDatabaseAlways
and DropCreateDatabaseIfModelChanges
functionality because I built a number of integration tests around the feature. Is there a more elegant want to attach to an SQL view than creating the table, dropping the table, and then creating the view with the sql command?
[Using VS2010 Professional, ASP.NET 4, MVC3, EF4, SQL Server 2008 R2 Express, Win7]
public MyContext : DbContext {
public DbSet<Person> Persons {get; set;}
public DbSet<Worker> Workers {get; set;}
public DbSet<Signin> Signins {get; set;}
public DbSet<SigninView> SigninView {get; set;}
}
public class Person
{
public int ID { get; set; }
public virtual Worker Worker { get; set; }
}
public class Worker
{
public int ID { get; set; }
public int barcodenumber {get; set;}
public virtual Person Person { get; set; }
public virtual ICollection<WorkerSignin> workersignins { get; set; }
}
public class WorkerSignin
{
public int ID { get; set; }
public virtual Worker worker {get; set;}
public int barcodenumber {get; set;}
}
Person.ID == Worker.ID. They're in a 1 to 0..1 relationship. There will always be a person; there may not be a worker record.
public class PersonBuilder : EntityTypeConfiguration<Person>
{
public PersonBuilder()
{
ToTable("Persons");
HasKey(k => k.ID);
HasOptional(p => p.Worker).WithRequired().WillCascadeOnDelete();
}
}
public class WorkerBuilder : EntityTypeConfiguration<Worker>
{
public WorkerBuilder()
{
HasKey(k => k.ID);
HasMany(s => s.workersignins)
.WithOptional(s => s.worker)
.HasForeignKey(s => s.WorkerID);
}
}
The Signin table receives input from a barcode scanner. Workers swipe a card and register for the day. The client requires that the the Signin be recorded even if there's no corresponding record in the Worker table at the time of the scan. Because of the client requirement, I am planning on using an ID I can control as the primary key, and correlate the barcodenumber programmatically or with a view where possible.
The SigninView combines information from the Person, Worker, and Signin tables to present on the webpage where the ID is getting swiped. I'm assuming that an SQL server view will be faster a view than my C# correlating 3 tables worth of data. (I don't feel I have time to stop and test this).
So...what I want to do is attach to the View. I can attach to the view using DbSet<>, but I'm also using CodeFirst to re-create my table structure as I develop the application.
Right now I have a kludge where Code-First creates a table SigninView, then dropping it and creating the view with SqlCommands:
public class MyInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext myDB)
{
myDB.Database.SqlCommand(@"drop table machete.dbo.WorkerSigninView");
myDB.Database.SqlCommand(@"CREATE VIEW [dbo].[WorkerSigninView]
AS
SELECT dbo.WorkerSignins.ID, dbo.WorkerSignins.barcodenumber
FROM dbo.Persons INNER JOIN
dbo.Workers ON dbo.Persons.ID = dbo.Workers.ID RIGHT OUTER JOIN
dbo.WorkerSignins ON dbo.Workers.barcodenumber = dbo.WorkerSignins.barcodenumber");
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Code First 目前不支持数据库视图,因此如果您想使用重新创建数据库,您必须使用您的方法、带有投影到数据类型的自定义 linq 查询(这是常见方法)或
SqlQuery
来直接执行您的 SELECT。Code first currently doesn't have support for database views so If you want to use recreate databese you must use either your approach, custom linq query with projection to data type (that is common approach) or
SqlQuery
to execute your SELECT directly.