简体   繁体   中英

c# linq join parent and child in generic extension method

i've got many ef core entities with a possibility to join a shared child table ( without FK-s). I created a generic join extension method, but got a bit stuck returning the main parent entity with the child mapped to it.

Heres what i've got:

public interface IBaseEntity
    {
        int Id { get; set; }
    }
 
public interface IBaseAttachmentEntity:IBaseEntity
    {
         ICollection<ResourceAttachment> ResourceAttachment { get; set; }
    }
public  class ResourceAttachment:BaseEntity
{
    //PK- Id of the parent table
    public long ParentId { get; set; }
    // type or enum of a parent table. Should point to which table it points to
    public string ResourceType { get; set; }
    
    public string AttachmentType { get; set; }

    public string Value { get; set; }
}


public static class EFCoreExtension
            {
    //this must be a generic method, want to use it for ~30 tables where the entity inherits IBaseAttachmentEntity
                public static IQueryable<TEntity> IncludeResourceAttachment<TEntity>
                    (this IQueryable<TEntity> queryable,IServiceProvider serviceProvider) where TEntity : class,IBaseAttachmentEntity
                {
                    var className = queryable.ElementType.Name;
                    var attachmentRepository = serviceProvider.GetRequiredService<IResourceAttachmentRepository>();
                    var attachments = attachmentRepository
                        .FindAllQueriable(x => x.ResourceType == className); //this part is fine 
         
                    var joined = (from q in queryable
                            join a in attachments on q.Id equals a.ParentId into qa
                            from a in qa.DefaultIfEmpty()
                            select  new {Parent=q,Attachments = qa}); // joining the child table, ending up with a tuple like result 
        
                    return joined.Select(x => x.Parent); // need to return the Parent together with Parent.ResourceAttachment which id defined in the 
                }          
    
            }

want to use the extension like this:

   var result =  _deviceServiceService.FindAllQueriable(CurrentUserId(), matchFilter)
                .IncludeResourceAttachment(_serviceProvider).ToList();

EDIT:

i have also created a minimal sample project to run. Uses In memory Db with data seeding

https://github.com/rauntska/EFGenericChildJoin

Thanks!

THis might not be what you want, but you might have to settle for it:

public static IEnumerable<TEntity> IncludeResourceAttachment<TEntity>
    (this IQueryable<TEntity> queryable, IServiceProvider serviceProvider) where TEntity : class, IBaseAttachmentEntity
{
    var className = queryable.ElementType.Name;
    var dataContext = serviceProvider.GetRequiredService<DataContext>();
    var attachments = dataContext.Set<ResourceAttachment>().Where(x => x.ResourceType == className);

    var joined =
        from q in queryable
        join a in attachments on q.Id equals a.ParentId into qa
        select new { Parent = q, Attachments = qa };

    foreach (var x in joined)
        foreach (var y in x.Attachments)
            x.Parent.ResourceAttachment.Add(y);
    
    return joined.Select(x => x.Parent);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM