简体   繁体   中英

How can transform this query to linq?

I'm trying get count of rows in another table. I need result count of tbl_result_subject_brand table with brand condution. I have a query for this situation:

SELECT tbl_brand.OID, (SELECT COUNT(*) FROM tbl_result_subject_brand WHERE tbl_result_subject_brand.brand_id = tbl_brand.OID) AS NewsCount FROM tbl_brand

This query is working fine but how can I transform this query to LINQ expression in ASP.NET? Really I dont know how to do it..

using (MuleContext muleContext = new MuleContext())
{
    list = (from b in muleContext.tbl_brand
            join rsb in muleContext.tbl_result_subject
            on new { brandID = rsb.BrandID }
            equals new { brandID = b.OID }
            select new NetNewsCounts
            {
                BrandID = b.OID,
                ResultCount= ???rsb.COUNT???,

            }).ToList();
}

Something like this, I guess.

class Test
    {
        public void TestMethod()
        {
            var repo = new Repository();
            var result = repo.tbl_brand
                   .Select(b => new NetNewsCounts()
                   {
                       BrandID = b.OID,
                       ResultCount = repo.tbl_result_subject_brand.Count(rb => rb.brand_id == b.OID)
                   }).ToList();
        }

        private class Brand
        {
            public string OID { get; set; }
        }

        private class ResultBrand
        {
            public string brand_id { get; set; }
        }

        private class Repository
        {
            public List<Brand> tbl_brand { get; set; }
            public List<ResultBrand> tbl_result_subject_brand { get; set; }
        }

        private class NetNewsCounts
        {
            public string BrandID { get; set; }

            public int ResultCount { get; set; }
        }
    }

If you are performing a normal join you will only get the results of ids that are on both tables. In case this is really what you wanted then you can simplify it and only query a single table:

var result = muleContext.tbl_result_subject
    .GroupBy(i => i.BrandID)
    .Select(i => new NetNewsCounts { BrandID = i.Key, ResultCount = g.Count() });

If you want ids that are in tbl_brand but might not be in tbl_result_subject then perform a left join similar to this: LINQ - Left Join, Group By, and Count . The projection part is similar to the one above.

You can simplify your query into a group by query:

SELECT OID, COUNT(*) 
FROM tbl_result_subject_brand
Group By OID

which can be translated into linq like this:

(from r in muleContext.tbl_result_subject_brand
group r by r.OID into g
select new NetNewsCounts { BrandID = g.Key, ResultCount= g.Count() }).ToList();

write like this

public List<Result> GetCount()
        {
            using (MuleContext db = new MuleContext())
            {


                var list = db.tbl_brand.Tolist();
                List<Result> GN = new List<Result>();
                foreach (var n in list)
                {
                    Result Notif = new Result()
                    {
                        OID = n.OID,

                   ResultCount=db.tbl_result_subject_brand.where(t=>t.brand_id=n.OID)
                    };
                    GN.Add(Notif);
                }
                return GN;
            }
        }

There are a couple of ways around this, but the simplest is the most direct equivalent. I'm assuming that your actual query requirement is that you get all OID values with counts - including 0s - of matching rows in the other table.

Here's your source query (reformatted and with some aliases to make it simpler):

SELECT 
    b.OID, 
    (
        SELECT COUNT(*) 
        FROM tbl_result_subject_brand rs
        WHERE rs.brand_id = b.OID
    ) AS NewsCount 
FROM tbl_brand b

We can do almost exactly the same thing in at least some LINQ ORMs:

using (var ctx = new MuleContext())
{
    var query = 
        from b in ctx.tbl_brand
        select new
        {
            b.OID,
            NewsCount = ctx.tbl_result_subject_brand.Count(rs => rs.brand_id == b.OID)
        };

    var list = query.ToList();
}

This works for me when using Linq2DB, which converts it to an SQL query that is basically identical to your original. Exactly the same structure anyway. Other ORMs might not be so OK with the above format.

The other option is groups and joins. Just be aware that joins are inner by default. You need to use join...into...DefaultIfEmpty to get a left outer join equivalent, then handle the missing values. It's a mildly painful process.

This has two forms: group-then-join or join-then-group. The first uses a sub-query to get the counts, then joins to that query to get the values you want:

var rsCounts = 
    from rs in ctx.tbl_result_subject_brand
    group 0 by rs.brand_id into grp
    select new { brand_id = grp.Key, NewsCount = (int?)grp.Count() };

var query =
    from b in ctx.tbl_brand
    join rs in rsCounts on b.OID equals rs.brand_id into rstmp
    from rs in rstmp.DefaultIfEmpty()

    select new
    {
        b.OID,
        NewsCount = rs.NewsCount ?? 0
    };

(You can do it in a single statement. It's harder to figure out what it's doing that way sometimes.)

The other version joins the tables together then groups on the relevant columns. This checks for missing rows using a Sum instead of Count :

var query = 
    from b in ctx.tbl_brand
    join rs in ctx.tbl_result_subject_brand on b.OID equals rs.brand_id into rstmp
    from rs in rstmp.DefaultIfEmpty()

    group (rs.brand_id == null ? 0 : 1) by b.OID into grp
    select new
    {
        OID = grp.Key,
        NewsCount = grp.Sum()
    };

Not pretty, but it works.

I'd suggest you have a look at what the SQL looks like when you run the above. Sometimes the SQL is a bit weird.

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