如何查询复杂的n:m关系以在C#中获取IEnumerable

时间:2019-03-18 12:51:02

标签: c# asp.net linq-to-sql

在我的sql数据库中,我具有如下所示的多对多(n:m)关系: table relationship

对于我的asp.net Web应用程序(使用EF和数据库优先方法),我需要提取属于同一关联成员的所有组的表Quality的所有记录(使用C#和linq)。

下面,我给出了示例数据,以说明G_Id = 1的给定组所需的查询结果

sample data

从样本数据中,我们看到给定的组是关联A_Id = 1和A_Id = 2的成员。因此,我们需要查看哪些其他组是这些关联的成员。在给定的数据中,我们看到G_Id = 2的组也是关联A_Id = 1的成员,而G_Id = 3的组也是A_Id = 2的成员。 因此,我们必须从表Quality中收集所有记录,其中G_Id = 1,G_Id = 2和G_Id = 3,查询结果为:

Query result

我能够编写一个有效的C#IEnumerable控制器操作(请参见下文)以获取一组的所有 Quality 记录,但未能提出一个查询,该查询也考虑了相关记录组。

public IEnumerable<Quality> Get()
{
    int g_Id = myAppPrincipal.G_Id;
    var group = UnitOfWork.GetById<Group>(g_Id);
    var groupQualities = group.Qualities;
    // Qualities is a public virtual ICollection of Quality inside the class Group

    IList<Quality> result = groupQualities.Select(entity => new Quality()
    {
        Q_Id = entity.Q_Id,
        Description = entity.Description,
        ...
    }).ToList();

    return result;
}

如果有人可以帮助我建立正确的查询,我将不胜感激。

请参见下面的类结构:

public class Entity
{
    /// <summary>
    /// Unique identifier
    /// </summary>
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public virtual int Id
    {
        get;
        set;
    }

    /// <summary>
    /// Concurrency check property
    /// </summary>
    [Timestamp]
    public virtual byte[] Version
    {
        get;
        set;
    }

    /// <summary>
    /// Determines whether entity is new
    /// </summary>
    [Bindable(false)]
    [ScaffoldColumn(false)]
    public virtual bool IsNew
    {
        get
        {
            return Id == 0;
        }
    }

    public override string ToString()
    {
        return this.DumpToString();
    }
}

public class Association: Entity
{
    public string Description { get; set; }
}

public class Assoc_Group: Entity
{
    public int A_ID { get; set; }
    public int G_ID { get; set; }

    [IgnoreDataMember]
    public override byte[] Version
    {
        get;
        set;
    }
}

public class Group: Entity
{
    public Group()
    {
        Qualities = new List<Quality>();
    }

    public string Description { get; set; }

    public virtual ICollection<Quality> Qualities { get; set; }

}

public class Quality: Entity
{
    public int? G_ID { get; set; }
    public string Description { get; set; }

    public virtual Group Group { get; set; }

    [IgnoreDataMember]
    public override byte[] Version
    {
        get;
        set;
    }
}

及其对应的映射:

public class AssociationMap : EntityTypeConfiguration<Association>
{
    public AssociationMap()
    {
        // Primary Key
        HasKey(t => t.Id);

        // Properties
        Property(t => t.Description)
            .IsRequired();

        // Table & Column Mappings
        ToTable("Association");
        Property(t => t.Id).HasColumnName("A_ID");
        Property(t => t.Description).HasColumnName("Description");

        Ignore(t => t.Version);
    }
}

class Assoc_GroupMap : EntityTypeConfiguration<Assoc_Group>
{
    public Assoc_GroupMap()
    {

        ToTable("Assoc_Group");
        Property(t => t.Id).HasColumnName("AG_ID");
        Property(t => t.A_ID).HasColumnName("A_ID");
        Property(t => t.G_ID).HasColumnName("G_ID");

        Ignore(property => property.Version);
    }
}

public class GroupMap : EntityTypeConfiguration<Group>
{
    public GroupMap()
    {
        // Primary Key
        HasKey(t => t.Id);

        // Table & Column Mappings
        ToTable("Group");
        Property(t => t.Id).HasColumnName("G_ID");


        Ignore(t => t.Version);
    }
}


public class QualityMap : EntityTypeConfiguration<Quality>
{
    public QualityMap()
    {
        // Primary Key
        HasKey(t => t.Id);

        // Table & Column Mappings
        ToTable("Quality");
        Property(t => t.Id).HasColumnName("Q_ID");
        Property(t => t.G_ID).HasColumnName("G_ID");
        ...

        // Relationships
        HasOptional(t => t.Group)
            .WithMany(t => t.Qualities)
            .HasForeignKey(d => d.G_ID);
    }
}

2 个答案:

答案 0 :(得分:1)

据我了解,您需要属于某个特定组的所有父级关联的所有组质量,所以:

public IEnumerable<Quality> Get()
{
    int g_Id = myAppPrincipal.G_Id;
    var group = UnitOfWork.GetById<Group>(g_Id);
    var associatedGroups = group.Assoc_Group.Groups;
    var qualities = new List<Quality>();
    foreach (var assoc in associatedGroups.Select(t => t.Association).Distinct())
    {
        qualities.AddRange(assoc.Assoc_Groups.SelectMany(t => t.group.Qualities).ToList());
    }

    var result = qualities.Distinct();
    return result;
}

在上述情况下,我希望 GetById 也能获取关联的实体,如果没有,则必须更改为 GetById 方法以包括关联的实体。否则,您可以通过单独调用来分别获得关联。

答案 1 :(得分:1)

您可以使用如下嵌套查询:

db.my_products.find({mak_salesRank:"Software"}, {Software: 1})
              .sort({Software: -1})
              .limit(1)

至少对于SQL Server。

您可以在这里尝试:http://sqlfiddle.com/#!18/6dcc6/2

要使用C#查询SQL数据库,可以使用SqlClient

DECLARE @GivenGroup AS Int = 1

SELECT DISTINCT Q_Id
FROM Quality q
WHERE q.G_Id IN
(
    SELECT DISTINCT G_Id
    FROM Assoc_Group ag
    WHERE ag.A_Id IN
    (
        SELECT a.A_Id
        FROM Association a
        INNER JOIN Assoc_Group ag ON a.A_Id = ag.A_Id
        WHERE ag.G_Id = @GivenGroup
    )
)

可能包含错误。