《Entity Framework 6 Recipes》中文翻译——第九章EntityFramework在N层架构程序中的应用(二)
在WCF中更新断开实体
问题
你想使用Windows通信基础(WCF)服务来显示选择、插入、删除和更新数据存储中的数据,并尽可能简单地保存数据库操作。此外,您要使用EntityFramework6 中的First-Code方法来实现数据访问。
解决方案
你有以下模型:
我们的模型代表blog的文章Post,以及Post的读者评论Comment。为了让事情更清楚,我们已经剥离了我们通常会用到的大部分属性。我们要把所有的数据库代码写在后面一个WCF服务中,使客户可以读取、更新和删除帖子和评论,以及插入新的。要创建服务,做以下工作:
1、创建一个类库程序,命名为Recipe2
2、添加EF6的引用,可以使用NuGet Package Manager实现:右击引用,选择NuGet Package Manager,选择EntityFramework6 ,进行加载和安装
3、添加三个类到Recipe2程序中:Post、Comment、Recipe2Context。Post和Comment代表的POCO实体类,将直接映射到相应的Post和Comment表。recipe2context是数据库上下文对象,将作为实体框架功能的网关。确保你包括所需的WCF数据合同和数据实体类的成员属性
[DataContract(IsReference = true)] public class Post { public Post() { Comments = new HashSet<Comment>(); } [DataMember] public int PostId { get; set; } [DataMember] public string Title { get; set; } [DataMember] public virtual ICollection<Comment> Comments { get; set; } }
[DataContract(IsReference = true)] public class Comment { [DataMember] public int CommentId { get; set; } [DataMember] public int PostId { get; set; } [DataMember] public string CommentText { get; set; } [DataMember] public virtual Post Post { get; set; } }
public class EFRecipesEntities : DbContext { public EFRecipesEntities() : base("name=EFRecipesEntities") { this.Configuration.ProxyCreationEnabled = false; } public DbSet<Post> Posts { get; set; } public DbSet<Comment> Comments { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Post>() .HasMany(e => e.Comments) .WithRequired(e => e.Post) .WillCascadeOnDelete(false); } }
4、在App.Config中添加链接
<connectionStrings> <add name="EFRecipesEntities" connectionString="data source=.;initial catalog=School4;persist security info=True;user id=sa;password=123;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> </connectionStrings>
5、接下来添加WCF服务应用程序,为了简单就直接用默认名称作为项目名称,修改IService.cs。添加Recipe2程序和EntityFramework6的引用
[ServiceContract] public interface IService1 { [OperationContract] void Cleanup(); [OperationContract] Post GetPostByTitle(string title); [OperationContract] Post SubmitPost(Post post); [OperationContract] Comment SubmitComment(Comment comment); [OperationContract] void DeleteComment(Comment comment); }
6、用以下代码替换Service1.svc.cs 文件中的内容
public class Service1 : IService1 { public void Cleanup() { using (var context = new EFRecipesEntities()) { context.Database.ExecuteSqlCommand("delete from chapter9.comment"); context.Database.ExecuteSqlCommand("delete from chapter9.post"); } } public void DeleteComment(Comment comment) { using (var context = new EFRecipesEntities()) { context.Entry(comment).State = EntityState.Deleted; context.SaveChanges(); } } public Post GetPostByTitle(string title) { using (var context = new EFRecipesEntities()) { context.Configuration.ProxyCreationEnabled = false; var post = context.Posts.Include(p => p.Comments)//System.Data.Entity.dll .Single(p => p.Title == title); return post; } } public Comment SubmitComment(Comment comment) { using (var context = new EFRecipesEntities()) { context.Comments.Attach(comment); if (comment.CommentId == 0) { // this is an insert context.Entry(comment).State = EntityState.Added); } else { // set single property to modified, which sets state of entity to modified, but // only updates the single property – not the entire entity context.Entry(comment).Property(x => x.CommentText).IsModified = true; } context.SaveChanges(); return comment; } } public Post SubmitPost(Post post) { using (var context = new EFRecipesEntities()) { context.Entry(post).State = // if Id equal to 0, must be insert; otherwise, it's an update post.PostId == 0 ? EntityState.Added : EntityState.Modified; context.SaveChanges(); return post; } } }
7、添加Windows Console Application程序作为我们的客户端来测试WCF服务,添加服务引用,同时更新Program.cs文件
class Program { static void Main(string[] args) { using (var client = new ServiceReference1.Service1Client()) { // cleanup previous data client.Cleanup(); // insert a post var post = new Post { Title = "POCO Proxies" }; post = client.SubmitPost(post); // update the post post.Title = "Change Tracking Proxies"; client.SubmitPost(post); // add a comment var comment1 = new Comment { CommentText = "Virtual Properties are cool!", PostId = post.PostId }; var comment2 = new Comment { CommentText = "I use ICollection<T> all the time", PostId = post.PostId }; comment1 = client.SubmitComment(comment1); comment2 = client.SubmitComment(comment2); // update a comment comment1.CommentText = "How do I use ICollection<T>?"; client.SubmitComment(comment1); // delete comment 1 client.DeleteComment(comment1); // get posts with comments var p = client.GetPostByTitle("Change Tracking Proxies"); Console.WriteLine("Comments for post: {0}", p.Title); foreach (var comment in p.Comments) { Console.WriteLine(" Comment: {0}", comment.CommentText); } } } }
运行结果