C# 实体框架(代码优先),在模型上实现 CRUD 操作



我只是想知道你是否可以在模型中存储一个函数(CRUD事务( 这将看起来像这样:

我现有的代码:

public class tbluser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Required(ErrorMessage = "Username is required")]
public string username { get; set; }
[Required(ErrorMessage = "Password is required")]
public string password { get; set; }
public static List<tbluser> list()
{
using (var db = new sample())
{
var user = db.tbluser.ToList();
return user;
}
}
}

我想要什么:

public class tbluser:DbContext
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Required(ErrorMessage = "Username is required")]
public string username { get; set; }
[Required(ErrorMessage = "Password is required")]
public string password { get; set; }

public static List<tbluser> list()
{
return this.toList();
}
}

我还想问一下实现实体框架的方法是否可以。

下面是一个快速示例,说明如何设置简单的 Code First 实现以开始使用。

首先,定义您的用户模型。整数类型的 Key 属性会自动为您配置标识属性。然后,如果您计划按用户名进行频繁查找(以获取用户详细信息或验证密码(,则可能需要用户名索引。

public class User
{
[Key] // Becomes identity by default
public int Id { get; set; }
[Index("IX_User_Username", IsUnique = true)]
public string Username { get; set; }
public string Password { get; set; }
}

然后,您可以定义

public class AppDataContext : DbContext
{
public AppDataContext() : base("name=DBConnection") { }
public DbSet<User> Users { get; set; }
}

你只需要确保配置文件中有一个连接字符串来匹配那里传递的名称。

<connectionStrings>
<add name="DBConnection"  providerName="System.Data.SqlClient"
connectionString="Data Source=instancePath;Initial Catalog=dbName;Integrated Security=true;MultipleActiveResultSets=True" />
</connectionStrings>

现在,这将允许您创建如下所示的存储库:

public class UserRepo : IDisposable
{
public Lazy<AppDataContext> _db = new Lazy<AppDataContext>(() => new AppDataContext());
public IQueryable<User> Get() => _db.Value.Users.AsQueryable();
public IList<User> GetAll() => _db.Value.Users.ToList();
public void Dispose()
{
if (_db.IsValueCreated)
_db.Value.Dispose();
}
}

因此,您可以直接使用存储库或上下文。

// Use the repo
using (var userRepo = new UserRepo())
{
var allUsers = userRepo.GetAll();
var user = userRepo.Get().FirstOrDefault(m => m.Username == "myUsername");
}
// Or just use the data context
using (var db = new AppDataContext())
{
var allUsers = db.Users.ToList(); // Get all users
var user = db.Users.FirstOrDefault(m => m.Username == "myUsername");
}

有关更多信息,以下是一些包含详细信息的有用链接:

  • 简单示例
  • 数据注释
  • 初始值设定项配置
  • 迁移

像这样的代码将存在严重问题。

在第一个示例中,您将 DbContext 的实例与实体紧密耦合。调用 tblUser.list(( 将返回用户实体的列表,但这些实体现在将超出 DbContext 的范围。(由于using()块关闭(这意味着检索相关实体的任何延迟加载调用都将失败,并且您无法保留对实体的任何更改,直到它们重新附加到另一个 DbContext。这变得非常混乱,非常快。

在第二个示例中,您将扩展 DbContext,这意味着每个"实体"都在有效地限定 DbContext 用于填充自身实例的范围。您不能只"静态"包装该方法,因为这对从 DbContext 继承的非静态 DbSet 不可见。

这在性能方面是可怕的,从代码的角度来看,这看起来很奇怪:

using (var user = new tbluser)
{
var users = user.list(); // not static.
// .. Do stuff..
}

使其静态将是有问题的,因为 DbContext 需要在 tbluser 中具有静态作用域

public class tbluser
{
private static MyContext _context = new MyContext();
// ...
public static List<tbluser> list()
{
return _context.tblusers.ToList();
}
}

这可能仍然存在问题,例如静态实例在远程运行之前如何处置,但我当然不能推荐这样的方法。

相反,请按预期使用 DbContext。查看 Unity 或 Autofac 等 IoC 容器来管理 DbContext 的生存期范围,并将实例作为依赖项注入到需要它的类中,或者至少将其包装在using() {}块中,并将其视为具有 DbSet 的存储库。

有很多有效使用 DbContext 的例子,使用存储库和工作单元模式以及依赖注入。在尝试旋转一些独特的东西之前掌握这些。未来的开发人员看到你的代码会感谢你。:)

有一个著名的原则叫做"关注点分离",如果你这样做,它会非常生气。我的建议是保持代码简单、有意义和松散耦合。