如何使用EF6处理TimeSpan并将其保存到SQLite数据库中
解决SQLite中EF无法存储TimeSpan类型的问题
这个问题很常见——SQLite本身并没有原生支持TimeSpan(对应EF中的Edm.Time)这种时间间隔类型,所以EF在映射时找不到对应的存储类型,就抛出了NotSupportedException。下面是几种可行的解决办法:
方法1:使用值转换器(Value Converter)将TimeSpan转为SQLite支持的类型
EF Core 2.1及以上版本支持值转换器,可以轻松把TimeSpan转换成SQLite能存储的整数(比如Ticks)或字符串。最推荐的是转成Ticks,因为效率高且便于计算:
步骤1:在DbContext中配置转换器
修改你的MyDataContext,在OnModelCreating方法里为Time属性添加转换规则:
public class MyDataContext : DbContext { public DbSet<SomeModel> SomeModels { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite("Data Source=your_database.db"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置TimeSpan与Ticks的双向转换 modelBuilder.Entity<SomeModel>() .Property(s => s.Time) .HasConversion( // 保存时:TimeSpan转成Ticks(long类型) timeSpan => timeSpan.Ticks, // 读取时:Ticks转回TimeSpan ticks => TimeSpan.FromTicks(ticks)) // 指定SQLite中的列类型为INTEGER .HasColumnType("INTEGER"); } }
步骤2:重新运行你的代码
现在再执行你原来的添加数据代码,EF会自动处理TimeSpan和整数之间的转换,不会再抛出异常。
如果你更倾向于用字符串存储(比如可读性更好),也可以用字符串转换器:
.HasConversion( timeSpan => timeSpan.ToString(), str => TimeSpan.Parse(str)) .HasColumnType("TEXT");
方法2:替换TimeSpan为DateTime(不推荐,但可行)
如果你不想用转换器,也可以把模型里的TimeSpan改成DateTime,只存储时间部分。不过这种方法需要额外处理数据转换,比如:
public class SomeModel { [Key] public int SomeInt { get; set; } public string SomeString { get; set; } // 用DateTime替代TimeSpan public DateTime Time { get; set; } }
然后在赋值时:
var item = new SomeModel { SomeInt = 123, SomeString = "a string", // 将TimeSpan转成DateTime(日期部分用默认值即可) Time = DateTime.Today.Add(new TimeSpan(1,2,3)) };
这种方法的缺点是语义不够清晰,而且查询时需要额外处理日期部分,所以更推荐第一种方法。
内容的提问来源于stack exchange,提问作者TomTomB
相关产品推荐
相关产品推荐

