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

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

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

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

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

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

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

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

  1. 在ASP.NET MVC4中实现同页面增删改查,无弹出框02,增删改查界面设计

    在上一篇"在ASP.NET MVC4中实现同页面增删改查,无弹出框01,Repository的搭建"中,已经搭建好了Repository层,本篇就剩下增删改查的界面了......今 ...

  2. 权限管理系统之LayUI实现页面增删改查和弹出层交互

    由于对LayUI框架不太熟悉,昨天抽空看了下LayUI的文档,今天在网上找了使用LayUI进行增删改查相关内容,自己照葫芦画了个瓢,画瓢部分不是很难,主要是下午遇到了一个弹出层的问题耗时比较久. 同一 ...

  3. ASP.NET Web API基于OData的增删改查,以及处理实体间关系

    本篇体验实现ASP.NET Web API基于OData的增删改查,以及处理实体间的关系. 首先是比较典型的一对多关系,Supplier和Product. public class Product { ...

  4. [转]ASP.NET Web API基于OData的增删改查,以及处理实体间关系

    本文转自:http://www.cnblogs.com/darrenji/p/4926334.html 本篇体验实现ASP.NET Web API基于OData的增删改查,以及处理实体间的关系. 首先 ...

  5. 用CI框架向数据库中实现简单的增删改查

    以下代码基于CodeIgniter_2.1.3版 用PHP向数据库中实现简单的增删改查(纯代码)请戳 http://www.cnblogs.com/corvoh/p/4641476.html Code ...

  6. dbutils中实现数据的增删改查的方法,反射常用的方法,绝对路径的写法(杂记)

    jsp的三个指令为:page,include,taglib... 建立一个jsp文件,建立起绝对路径,使用时,其他jsp文件导入即可 导入方法:<%@ include file="/c ...

  7. 快速开发平台WebBuilder中ExtJS表格的增删改查

    使用WebBuilder可实现表格的自动增删改查功能,而无需编写前台脚本和后台SQL. WebBuilder开源项目地址:http://www.putdb.com 自动生成的页面: <!DOCT ...

  8. MVC中的Ajax与增删改查

    自入手新项目以来,一直处于加班状态,博客也有两周没更,刚刚完成项目的两个模组,稍有喘息之机,写写关于项目中 的增删改查,这算是一个老生常谈的问题了,就连基本的教材书上都有.刚看书的时候,以为 没什么可 ...

  9. Android中Sqlite数据库进行增删改查

    今天这篇文章写Sqlite数据库,通过一个小案例来完整讲一下数据库常见的CRUD操作. 先对知识点总结: SQLite数据库 轻量级关系型数据库 创建数据库需要使用的api:SQLiteOpenHel ...

随机推荐

  1. 002_分布式搜索引擎Elasticsearch的查询与过滤

    一.写入 先来一个简单的官方例子,插入的参数为-XPUT,插入一条记录. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 curl -XPUT 'http:/ ...

  2. 001_fpm打包命令详解

    使用fpm来制作rpm包 2017/2/22 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ...

  3. jenkins之参数化构建

    事件背景: 今天一早接到一个需求,说要jenkins持续集成,输入自定义URL,然后完成回归测试,当时有点蒙,不知道如何下手,听群里的大神思路后豁然开朗,就记录了下 一.先安装插件 插件: [Buil ...

  4. crontab挂定时任务

    Linux shell基本知识 a)">"  与 ">>"  的作用是不一样的,前者使用本次输出内容替换原有文件的内容,后者则是把本次输出追加 ...

  5. KnockoutJs学习笔记(八)

    with binding用于创建一个新的绑定环境(binding context),包含with binding的元素的所有子元素都将处于指定的object的环境限定内. 下面是一个简单的使用with ...

  6. 关于调用&&传址

    关于调用&&传址//数组int d1[];Function(int *d){} int main(){Function(d1);} //指针int *p;Function(int *q ...

  7. 010.Zabbix的zatree插件安装

    一 zatree简介 zatree 是来自国内58公司开发的监控软件zabbix的一个插件,主要功能是提供host group的树形展示和在item里指定关键字查询及数据排序. 二 安装前准备 2.1 ...

  8. 【翻译】checkbox的第三种状态

    checkbox只有两种值:选中(checked)或未选中(unchecked).它可以有任何值,但是表单提交时checkbox的值只能是checked或unchecked.它的默认值是uncheck ...

  9. linux学习笔记-13.进程控制

    1.查看用户最近登录情况 lastlastlog 2.查看硬盘使用情况 df 3.查看文件大小 du 4.查看内存使用情况 free 5.查看文件系统 /proc 6.查看日志 ls /var/log ...

  10. Django中的ORM关系映射查询方面

    ORM:Object-Relation Mapping:对象-关系映射 在MVC框架中的Model模块中都包括ORM,对于开发人员主要带来了如下好处: 实现了数据模型与数据库的解耦,通过简单的配置就可 ...