在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层等"。

 

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

你可能感兴趣的:(repository)