Entity framework 跳过一个数据库字段值
Entity framework skip one db field value
我有一个非常小的项目,只是为了了解 'code first' 方法。
当我使用 'code first' 创建数据库并添加对象时 - 它运行良好,对象的所有属性都保存在数据库中。
然后我尝试获取保存的对象。它 returns 对象,但一个 属性 始终为空。
有人能解释一下我的代码有什么问题吗?
实体class
public class Item
{
public Guid Id { get; set; }
public string OwnerId { get; set; }
public DateTime CreationDate { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsStoreItem { get; set; }
public decimal Price { get; set; }
public int Count { get; set; }
public string TopBidderId { get; set; }
public Material Material { get; set; }
public ItemStatus Status { get; set; }
public int KrauseNumber { get; set; }
}
数据库实体
public class ApplicationDbContext : IdentityDbContext<ApplicationIdentityUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false) { }
public DbSet<Item> Items { get; set; }
public static ApplicationDbContext Create() => new ApplicationDbContext();
}
}
通用回购
public class EfGenericRepository<T> : IEfGenericRepository<T> where T : class
{
internal readonly ApplicationDbContext _dbContext;
internal readonly DbSet<T> _dbSet;
public EfGenericRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
public virtual IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
IQueryable<T> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
}
尝试获取实体
public void GetEntity(Guid id)
{
var context = new Repository();
var auction = context.ItemRepository.Get().FirstOrDefault(i => i.Id == id);
}
结果是
更新
另外我必须说,
var request = "SELECT TopBidderId FROM Items WHERE Id = '*item_id*'";
var result = _dbContext.Database.SqlQuery<string>(request).FirstOrDefaultAsync().Result;
效果很好,它 returns 绝对正确的值。
目前最简单的检测问题实际出在哪里的方法是查看由 Get 执行的生成的 select 语句。对于 Entity Framework 6 :
public EfGenericRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
_dbContext.Database.Log = Console.Write;
}
通过这个你将看到真正执行的脚本,让你更清楚地了解坠落的确切位置。
关于模型,我认为 Material 和 ItemStatus 是枚举,否则我建议将属性标记为虚拟(用于延迟加载)。
我也不太确定您的存储库实现。每个 EfGenericRepository 都有自己的上下文,我不确定这是否是一个好的设计,反正不是问题的主题。
答案:
您的模型包含一个名为 TopBidderId 的字符串 属性。当您创建数据库时,字段类型类似于 'text'(在最近的 SQL 服务器中为 varchar(max),在 MySQL、CLOB 中为文本,等等)。所以,在里面,你可以写一个字符串。在您的情况下,它似乎是 Guid 的 ToString。当您阅读内容时,字符串会插入到 TopBidderId 属性.
这不可能不会发生,文本(或 varchar(max))列可以转换为模型的 TopBidderId 的字符串。
顺便说一句,我尝试 运行 您的代码(从上下文而不是 IdentityDbContext 开始,添加两个缺少的枚举和存储库 class,默认迁移)并且它有效正如预期的那样。
那么为什么在您的情况下不起作用?我认为您的数据库模型与您的实体模型不一致(并且列 TopBidderId 不是文本或 varchar max)。通常它不会发生,但在某些情况下可能会发生。例如,如果您禁用模型检查(在您的实体模型和 __MigrationHistory table 的内容之间进行检查)或者您在迁移数据库后更改了 TopBidderId 列类型。
另一种情况是您的实体模型与您在此处发布的实体模型不同(并且 TopBidderId 是 Bidder 类型的 属性 TopBidder 使用的外键)。
我有一个非常小的项目,只是为了了解 'code first' 方法。
当我使用 'code first' 创建数据库并添加对象时 - 它运行良好,对象的所有属性都保存在数据库中。 然后我尝试获取保存的对象。它 returns 对象,但一个 属性 始终为空。
有人能解释一下我的代码有什么问题吗?
实体class
public class Item
{
public Guid Id { get; set; }
public string OwnerId { get; set; }
public DateTime CreationDate { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsStoreItem { get; set; }
public decimal Price { get; set; }
public int Count { get; set; }
public string TopBidderId { get; set; }
public Material Material { get; set; }
public ItemStatus Status { get; set; }
public int KrauseNumber { get; set; }
}
数据库实体
public class ApplicationDbContext : IdentityDbContext<ApplicationIdentityUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false) { }
public DbSet<Item> Items { get; set; }
public static ApplicationDbContext Create() => new ApplicationDbContext();
}
}
通用回购
public class EfGenericRepository<T> : IEfGenericRepository<T> where T : class
{
internal readonly ApplicationDbContext _dbContext;
internal readonly DbSet<T> _dbSet;
public EfGenericRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
public virtual IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
IQueryable<T> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
}
尝试获取实体
public void GetEntity(Guid id)
{
var context = new Repository();
var auction = context.ItemRepository.Get().FirstOrDefault(i => i.Id == id);
}
结果是
更新
另外我必须说,
var request = "SELECT TopBidderId FROM Items WHERE Id = '*item_id*'";
var result = _dbContext.Database.SqlQuery<string>(request).FirstOrDefaultAsync().Result;
效果很好,它 returns 绝对正确的值。
目前最简单的检测问题实际出在哪里的方法是查看由 Get 执行的生成的 select 语句。对于 Entity Framework 6 :
public EfGenericRepository(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
_dbContext.Database.Log = Console.Write;
}
通过这个你将看到真正执行的脚本,让你更清楚地了解坠落的确切位置。
关于模型,我认为 Material 和 ItemStatus 是枚举,否则我建议将属性标记为虚拟(用于延迟加载)。
我也不太确定您的存储库实现。每个 EfGenericRepository 都有自己的上下文,我不确定这是否是一个好的设计,反正不是问题的主题。
答案:
您的模型包含一个名为 TopBidderId 的字符串 属性。当您创建数据库时,字段类型类似于 'text'(在最近的 SQL 服务器中为 varchar(max),在 MySQL、CLOB 中为文本,等等)。所以,在里面,你可以写一个字符串。在您的情况下,它似乎是 Guid 的 ToString。当您阅读内容时,字符串会插入到 TopBidderId 属性.
这不可能不会发生,文本(或 varchar(max))列可以转换为模型的 TopBidderId 的字符串。
顺便说一句,我尝试 运行 您的代码(从上下文而不是 IdentityDbContext 开始,添加两个缺少的枚举和存储库 class,默认迁移)并且它有效正如预期的那样。
那么为什么在您的情况下不起作用?我认为您的数据库模型与您的实体模型不一致(并且列 TopBidderId 不是文本或 varchar max)。通常它不会发生,但在某些情况下可能会发生。例如,如果您禁用模型检查(在您的实体模型和 __MigrationHistory table 的内容之间进行检查)或者您在迁移数据库后更改了 TopBidderId 列类型。
另一种情况是您的实体模型与您在此处发布的实体模型不同(并且 TopBidderId 是 Bidder 类型的 属性 TopBidder 使用的外键)。