博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

EF Core经验

Posted on 2025-04-15 17:04  火冰·瓶  阅读(33)  评论(0)    收藏  举报

1.使用了db first 后,增加额外的显式配置外键而不影响自动生成的配置

加入有2个表,分别是TaskInfo(任务表),和TaskInfoSubmitResumeRecord(任务提交记录表)

TaskInfo和TaskInfoSubmitResumeRecord是一对多的关系

在TaskInfoSubmitResumeRecord中有一个字段TaskId指向TaskInfo的主键(数据库中不用设置外键,设置了会自动生成导航属性和配置)

需要建3个部分类分别为:

public partial class TaskInfo
{
  // 导航属性
  public virtual ICollection<TaskInfoSubmitResumeRecord>? TaskInfoSubmitResumeRecords { get; set; }
}



public partial class TaskInfoSubmitResumeRecord
{
  //导航属性
  public virtual TaskInfo? TaskInfo { get; set; }
}



public partial class MySqlTrainDbContext
{
    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TaskInfoSubmitResumeRecord>()
                .HasOne(c => c.TaskInfo)
                .WithMany(p => p.TaskInfoSubmitResumeRecords)
                .HasForeignKey(c => c.TaskId);
    }
}

 

Copilot中的建议

EF Core 中,即使没有外键,你仍然可以定义 导航属性 来建立实体之间的关系。通常有以下几种方法:

方法 1:使用 virtual 导航属性

即使没有外键,你仍然可以在实体类中定义导航属性:

public class Parent
{
    public int Id { get; set; }
    public string Name { get; set; }

    // 导航属性
    public virtual ICollection<Child> Children { get; set; }
}

public class Child
{
    public int Id { get; set; }
    public string Name { get; set; }

    // 导航属性
    public virtual Parent Parent { get; set; }
}

这样,EF Core 仍然可以在查询Includ时填充 ChildrenParent,但不会自动创建外键。  

方法 2:使用 Fluent API 显式配置关系

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Child>()
        .HasOne(c => c.Parent)
        .WithMany(p => p.Children)
        .HasForeignKey("ParentId") // 这里不定义外键字段
        .IsRequired(false); // 允许为空
}

方法 3:使用 Shadow Property

如果你不想在实体类中定义外键字段,可以使用 Shadow Property

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Child>()
        .Property<int>("ParentId"); // 影子属性
}

 

 

 

2.将Lambda表达式作为参数传递给方法

EF Core 中,你可以将 Lambda 表达式 作为参数传递给方法,以便动态构建查询。通常有以下几种方式:

1. 直接传递 Lambda 表达式

你可以创建一个方法,接受 Expression<Func<T, bool>> 作为参数:

public List<User> GetUsers(Expression<Func<User, bool>> predicate)
{
    using (var context = new MyDbContext())
    {
        return context.Users.Where(predicate).ToList();
    }
}



//然后调用
var users = GetUsers(u => u.Age > 18);

 

2. 使用泛型方法

如果你希望方法更加通用,可以使用泛型:

public List<T> GetEntities<T>(Expression<Func<T, bool>> predicate) where T : class
{
    using (var context = new MyDbContext())
    {
        return context.Set<T>().Where(predicate).ToList();
    }
}


//调用
var users = GetEntities<User>(u => u.Age > 18);

  

3. 结合 AsQueryable

如果你希望在不同的查询条件下复用 Lambda 表达式,可以使用 AsQueryable

Expression<Func<User, bool>> filter = u => u.Age > 18;
var users = context.Users.AsQueryable().Where(filter).ToList();

  

  

3.根据动态字段进行排序

string orderColumn = "Name"; // 通过外部传入字段名
query = query.OrderByDescending(x => EF.Property<object>(x, orderColumn));

 

如果要动态对父对象的字段名进行排序,使用System.Linq.Dynamic.Core

dotnet add package System.Linq.Dynamic.Core
using System.Linq.Dynamic.Core;

query = query.OrderBy("AddTime ascending"); //升序
query = query.OrderBy("AddTime descending");//降序

query = query.OrderBy("Account.AddTime ascending"); //升序   升序ascending可以省略
query = query.OrderBy("Account.AddTime descending");//降序


query = query.OrderBy("AddTime");  //升序可以不加ascending

判断对象属性的属性中是否包含排序字段,即上述例子中,判断属性Account中是否包含AddTime

            //判断排序字段是否在对象属性中
            if (type.GetProperty("Account") != null && type.GetProperty("Account").PropertyType.GetProperty("AddTime") != null) 
            {
                if (orderDir == "asc")
                {
                    recordsQuery = recordsQuery.OrderBy("Account.AddTime");
                }
                else
                {
                    recordsQuery = recordsQuery.OrderBy("Account.AddTime descending");
                }
            }

  

 

4.使用悲观锁,适用于高并发写入,如订单管理、库存更新

using var context = new MyDbContext();
await using var transaction = await context.Database.BeginTransactionAsync(); //开始加锁事务
var user = await context.Users.FirstOrDefaultAsync();
user.Name = "Updated Name";// 进行数据修改
await context.SaveChangesAsync();
await transaction.CommitAsync();//结束加锁事务