在ASP.NET MVC4中实现同页面增删改查,无弹出框01,Repository的搭建

通常,在同一个页面上实现增删改查,会通过弹出框实现异步的添加和修改,这很好。但有些时候,是不希望在页面上弹出框的,我们可能会想到Knockoutjs,它能以MVVM模式实现同一个页面上的增删改查,再辅以knockout.validation.js,还可以对Model进行验证。但knockout.validation.jsASP.NET MVC本身的验证没有做到无缝对接,不能形成一个从客户端到服务端连贯、统一的验证解决方案。关于在ASP.NET MVC中使用Knockoutjsknockout.validation.js,不知道各位朋友有没有好的案例?


于是,蓦然回首,jQuery在灯火阑珊处无比坚定地说:我已经和ASP.NET MVC联袂好久了,什么客户端验证、服务端验证,那都不是事!大致想做成这样:

 

显示的时候,只出现数据列表和搜索条件:
15

 

当点击"添加"按钮,在列表和搜索区域上方出现添加区域:
16

 

当点击"修改"按钮,在列表和搜索区域上方出现修改区域:
17


Repository的搭建

 

在Models文件夹下创建一个简单的领域模型。

namespace MvcApplication3.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }  
    }
}

 

通过EF Code First创建数据库初始数据。首先有一个派生于DbContext的EF上下文。

using System.Data.Entity;
namespace MvcApplication3.Models
{
    public class ProductContext : DbContext
    {
        public ProductContext() : base("conn")
        {
            Database.SetInitializer(new ProductInitializer());
        }
        public DbSet<Product> Products { get; set; }
    }
}

 

数据库数据的初始化工作是在ProductInitializer类中完成的。

using System.Data.Entity;
namespace MvcApplication3.Models
{
    public class ProductInitializer : DropCreateDatabaseIfModelChanges<ProductContext>
    {
        protected override void Seed(ProductContext context)
        {
            context.Products.Add(new Product() {Name = "秋意真浓", Price = 85M, Category = "散文"});
            context.Products.Add(new Product() {Name = "冬日恋歌", Price = 95M, Category = "小说" });
            context.Products.Add(new Product() { Name = "春暖花开", Price = 105M, Category = "散文" });
        }
    }
}

 

在Web.config中需要配置一下有关EF的连接字符串。

  <connectionStrings>
    ......
  <add name="conn" connectionString="Data Source=.;User=用户名;Password=密码;Initial Catalog=ProductStore;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

 

仓储层首先需要一个接口。

using System.Collections.Generic;
namespace MvcApplication3.Models
{
    public interface IProductRepository
    {
        IEnumerable<Product> GetAll(); //获取所有
        IEnumerable<Product> LoadProductPageData(ProductParam p, out int total);//获取分页数据
        Product GetById(int id); //根据id获取,通常显示更新页面时使用
        Product Add(Product item);//添加
        Product Update(Product item);//更新
        bool Delete(int id);//删除
        int DeleteBatch(string[] ids);//批量删除
    }
} 

 

仓储接口的实现通过EF上下文。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace MvcApplication3.Models
{
    public class ProductRepository : IProductRepository
    {
        private ProductContext db = new ProductContext();
        /// <summary>
        /// 获取所有
        /// </summary>
        /// <returns></returns>
        public System.Collections.Generic.IEnumerable<Product> GetAll()
        {
            return db.Products;
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="para">查询参数,包括:PageInde, PageSize,与Product有关的Name,Category</param>
        /// <param name="total">查询条件过滤之后的记录总数</param>
        /// <returns></returns>
        public IEnumerable<Product> LoadProductPageData(ProductParam para, out int total)
        {
            var products = db.Products.AsEnumerable();
            if (!string.IsNullOrEmpty(para.Name))
            {
                products = products.Where(p => p.Name.Contains(para.Name));
            }
            if (!string.IsNullOrEmpty(para.Category))
            {
                products = products.Where(p => p.Category.Contains(para.Category));
            }
            total = products.Count();
            IEnumerable<Product> result = products
                .OrderByDescending(x => x.Id)
                .Skip(para.PageSize * (para.PageIndex - 1))
                .Take(para.PageSize);
            return result;
        }
        /// <summary>
        /// 根据Id获取
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Product GetById(int id)
        {
            return db.Products.Find(id);
        }
        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public Product Add(Product item)
        {
            db.Products.Add(item);
            db.SaveChanges();
            return item;
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public Product Update(Product item)
        {
            try
            {
                if (item == null)
                {
                    throw new ArgumentException("Product不能为null");
                }
                var entry = db.Entry(item);
                if (entry.State == EntityState.Detached)
                {
                    var set = db.Set<Product>();
                    Product attachedProduct = set.Local.SingleOrDefault(p => p.Id == item.Id);
                    //如果已经被上下文追踪
                    if (attachedProduct != null)
                    {
                        var attachedEntry = db.Entry(attachedProduct);
                        attachedEntry.CurrentValues.SetValues(item);
                    }
                    else //如果不在当前上下文追踪
                    {
                        entry.State = EntityState.Modified;
                    }
                }
                db.SaveChanges();
                return item;
            }
            catch (Exception)
            {              
                throw;
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Delete(int id)
        {
            Product product = db.Products.Find(id);
            db.Products.Remove(product);
            if (db.SaveChanges() > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public int DeleteBatch(string[] ids)
        {
            foreach (string id in ids)
            {
                Delete(int.Parse(id));
            }
            return -1;
        }
        
    }
}

以上,需要特别说明的是Update方法,为类避免在更新的时候报类似"ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象"错,因为,在EF上上下文中是不允许存在2个具有相同键的实体的。在更新的时候,我们需要判断需要被更新的实体是否已经被当前上下文追踪。


当然,在三层架构中,我们可以通过CallContext线程槽获取到当前线程内的唯一EF上下文实例。详细做法请参考"MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等"。

 

下一篇进入增删改查的界面设计。

posted @ 2014-11-06 10:56  Darren Ji  阅读(4457)  评论(1编辑  收藏  举报

我的公众号:新语新世界,欢迎关注。