通常,在同一个页面上实现增删改查,会通过弹出框实现异步的添加和修改,这很好。但有些时候,是不希望在页面上弹出框的,我们可能会想到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. fish(自动推荐命令;语法高亮等)

    Fish 是 Linux/Unix/Mac OS 的一个命令行 shell,有一些很好用的功能. 自动推荐 VGA 颜色 完美的脚本支持 基于网页的配置 帮助文档自动补全 语法高亮 以及更多 自动推荐 ...

  2. springcloud Zuul中路由配置细节

    上篇文章我们介绍了API网关的基本构建方式以及请求过滤,小伙伴们对Zuul的作用应该已经有了一个基本的认识,但是对于路由的配置我们只是做了一个简单的介绍,本文我们就来看看路由配置的其他一些细节. 首先 ...

  3. 特性(C# 和 Visual Basic)

    特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联. 特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性. 有关更多信息,请参见 反射(C# 和 V ...

  4. 解决方案:centos运行shell脚本时报“$'\r': 未找到命令”

    =============================================== 2018/9/12_第1次修改                       ccb_warlock == ...

  5. poj1142

    分解质因数 #include <iostream> #include <cmath> using namespace std; int sum(int n) { ; ) { a ...

  6. 【OpenCV for Android】Android Studio集成OpenCV

    准备工作 1.下载安装Android Studio(过程略). 2.下载Android OpenCV:https://opencv.org/releases.html,找到Android pack点击 ...

  7. Java编程的逻辑 (65) - 线程的基本概念

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  8. Scala 学习笔记(2)之类和对象

    Scala 的类大抵和 Java 是类似的,简单的例子如下: class MyClass { var myField : Int = 0; def this(value : Int) = { this ...

  9. 一步一步学习IdentityServer3 (1)

    学习之初: IdentityServer3我自己最开始了解到的就是做一个SSO单点登录,后面发现还有单独的认证服务功能,其实它还可以做APIs的访问控制,资源授权,另外还可以为提供第三方登录,其他的自 ...

  10. JavaScript实现链式调用

    学习Jquery的时候,我们通常会看到链式调用的写法 $(window).addEvent('load', function(){ $('test').show().setStyle('color', ...