मैं इस क्वेरी को कैसे बदलूं ताकि यह सभी u.usergroups वापस आए?
from u in usergroups
from p in u.UsergroupPrices
select new UsergroupPricesList
{
UsergroupID = u.UsergroupID,
UsergroupName = u.UsergroupName,
Price = p.Price
};
जवाबों:
MSDN से अनुकूलित, EF 4 का उपयोग करके बाएं से कैसे जुड़ें
var query = from u in usergroups
join p in UsergroupPrices on u.UsergroupID equals p.UsergroupID into gj
from x in gj.DefaultIfEmpty()
select new {
UsergroupID = u.UsergroupID,
UsergroupName = u.UsergroupName,
Price = (x == null ? String.Empty : x.Price)
};
from x in gj.DefaultIfEmpty()
बन जाता है from p in gj.DefaultIfEmpty()
। docs.microsoft.com/en-us/ef/core/querying/…
यह थोड़ा अधिक हो सकता है, लेकिन मैंने एक विस्तार विधि लिखी है, इसलिए आप सिंटैक्स LeftJoin
का उपयोग कर सकते हैं Join
(कम से कम विधि कॉल संकेतन में):
persons.LeftJoin(
phoneNumbers,
person => person.Id,
phoneNumber => phoneNumber.PersonId,
(person, phoneNumber) => new
{
Person = person,
PhoneNumber = phoneNumber?.Number
}
);
मेरा कोड वर्तमान एक्सप्रेशन ट्री में a GroupJoin
और SelectMany
कॉल जोड़ने के अलावा और कुछ नहीं करता है । फिर भी, यह बहुत जटिल लग रहा है क्योंकि मुझे अभिव्यक्तियों का निर्माण स्वयं करना है और resultSelector
LINQ-to-Entities द्वारा पूरे पेड़ को अनुवाद योग्य बनाए रखने के लिए पैरामीटर में उपयोगकर्ता द्वारा निर्दिष्ट अभिव्यक्ति ट्री को संशोधित करना है ।
public static class LeftJoinExtension
{
public static IQueryable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
this IQueryable<TOuter> outer,
IQueryable<TInner> inner,
Expression<Func<TOuter, TKey>> outerKeySelector,
Expression<Func<TInner, TKey>> innerKeySelector,
Expression<Func<TOuter, TInner, TResult>> resultSelector)
{
MethodInfo groupJoin = typeof (Queryable).GetMethods()
.Single(m => m.ToString() == "System.Linq.IQueryable`1[TResult] GroupJoin[TOuter,TInner,TKey,TResult](System.Linq.IQueryable`1[TOuter], System.Collections.Generic.IEnumerable`1[TInner], System.Linq.Expressions.Expression`1[System.Func`2[TOuter,TKey]], System.Linq.Expressions.Expression`1[System.Func`2[TInner,TKey]], System.Linq.Expressions.Expression`1[System.Func`3[TOuter,System.Collections.Generic.IEnumerable`1[TInner],TResult]])")
.MakeGenericMethod(typeof (TOuter), typeof (TInner), typeof (TKey), typeof (LeftJoinIntermediate<TOuter, TInner>));
MethodInfo selectMany = typeof (Queryable).GetMethods()
.Single(m => m.ToString() == "System.Linq.IQueryable`1[TResult] SelectMany[TSource,TCollection,TResult](System.Linq.IQueryable`1[TSource], System.Linq.Expressions.Expression`1[System.Func`2[TSource,System.Collections.Generic.IEnumerable`1[TCollection]]], System.Linq.Expressions.Expression`1[System.Func`3[TSource,TCollection,TResult]])")
.MakeGenericMethod(typeof (LeftJoinIntermediate<TOuter, TInner>), typeof (TInner), typeof (TResult));
var groupJoinResultSelector = (Expression<Func<TOuter, IEnumerable<TInner>, LeftJoinIntermediate<TOuter, TInner>>>)
((oneOuter, manyInners) => new LeftJoinIntermediate<TOuter, TInner> {OneOuter = oneOuter, ManyInners = manyInners});
MethodCallExpression exprGroupJoin = Expression.Call(groupJoin, outer.Expression, inner.Expression, outerKeySelector, innerKeySelector, groupJoinResultSelector);
var selectManyCollectionSelector = (Expression<Func<LeftJoinIntermediate<TOuter, TInner>, IEnumerable<TInner>>>)
(t => t.ManyInners.DefaultIfEmpty());
ParameterExpression paramUser = resultSelector.Parameters.First();
ParameterExpression paramNew = Expression.Parameter(typeof (LeftJoinIntermediate<TOuter, TInner>), "t");
MemberExpression propExpr = Expression.Property(paramNew, "OneOuter");
LambdaExpression selectManyResultSelector = Expression.Lambda(new Replacer(paramUser, propExpr).Visit(resultSelector.Body), paramNew, resultSelector.Parameters.Skip(1).First());
MethodCallExpression exprSelectMany = Expression.Call(selectMany, exprGroupJoin, selectManyCollectionSelector, selectManyResultSelector);
return outer.Provider.CreateQuery<TResult>(exprSelectMany);
}
private class LeftJoinIntermediate<TOuter, TInner>
{
public TOuter OneOuter { get; set; }
public IEnumerable<TInner> ManyInners { get; set; }
}
private class Replacer : ExpressionVisitor
{
private readonly ParameterExpression _oldParam;
private readonly Expression _replacement;
public Replacer(ParameterExpression oldParam, Expression replacement)
{
_oldParam = oldParam;
_replacement = replacement;
}
public override Expression Visit(Expression exp)
{
if (exp == _oldParam)
{
return _replacement;
}
return base.Visit(exp);
}
}
}
कृपया अपने जीवन को आसान बनाएं (समूह में शामिल न हों):
var query = from ug in UserGroups
from ugp in UserGroupPrices.Where(x => x.UserGroupId == ug.Id).DefaultIfEmpty()
select new
{
UserGroupID = ug.UserGroupID,
UserGroupName = ug.UserGroupName,
Price = ugp != null ? ugp.Price : 0 //this is to handle nulls as even when Price is non-nullable prop it may come as null from SQL (result of Left Outer Join)
};
Price = ugp.Price
यदि Price
कोई अशक्त संपत्ति है और बायाँ जोड़ किसी भी परिणाम नहीं देता है, तो विफल हो सकता है ।
ugp == NULL
और के लिए एक डिफ़ॉल्ट मान सेट करें Price
।
यदि आप मेथड कॉल नोटेशन पसंद करते हैं, तो आप SelectMany
संयुक्त के साथ लेफ्ट जॉइन को बाध्य कर सकते हैं DefaultIfEmpty
। कम से कम इकाई फ्रेमवर्क पर 6 मार SQL सर्वर। उदाहरण के लिए:
using(var ctx = new MyDatabaseContext())
{
var data = ctx
.MyTable1
.SelectMany(a => ctx.MyTable2
.Where(b => b.Id2 == a.Id1)
.DefaultIfEmpty()
.Select(b => new
{
a.Id1,
a.Col1,
Col2 = b == null ? (int?) null : b.Col2,
}));
}
(ध्यान दें कि MyTable2.Col2
एक प्रकार का कॉलम है int
)। उत्पन्न SQL इस तरह दिखेगा:
SELECT
[Extent1].[Id1] AS [Id1],
[Extent1].[Col1] AS [Col1],
CASE WHEN ([Extent2].[Col2] IS NULL) THEN CAST(NULL AS int) ELSE CAST( [Extent2].[Col2] AS int) END AS [Col2]
FROM [dbo].[MyTable1] AS [Extent1]
LEFT OUTER JOIN [dbo].[MyTable2] AS [Extent2] ON [Extent2].[Id2] = [Extent1].[Id1]
2 और अधिक बाएं जोड़ों के लिए (बाएं शामिल होने वाले निर्माता और आरंभकर्ता)
IQueryable<CreateRequestModel> queryResult = from r in authContext.Requests
join candidateUser in authContext.AuthUsers
on r.CandidateId equals candidateUser.Id
join creatorUser in authContext.AuthUsers
on r.CreatorId equals creatorUser.Id into gj
from x in gj.DefaultIfEmpty()
join initiatorUser in authContext.AuthUsers
on r.InitiatorId equals initiatorUser.Id into init
from x1 in init.DefaultIfEmpty()
where candidateUser.UserName.Equals(candidateUsername)
select new CreateRequestModel
{
UserName = candidateUser.UserName,
CreatorId = (x == null ? String.Empty : x.UserName),
InitiatorId = (x1 == null ? String.Empty : x1.UserName),
CandidateId = candidateUser.UserName
};
मैं मुख्य मॉडल पर DefaultIfEmpty () को कॉल करके ऐसा करने में सक्षम था। इसने मुझे आलसी लोडेड संस्थाओं पर शामिल होने के लिए छोड़ दिया, मेरे लिए अधिक पठनीय लगता है:
var complaints = db.Complaints.DefaultIfEmpty()
.Where(x => x.DateStage1Complete == null || x.DateStage2Complete == null)
.OrderBy(x => x.DateEntered)
.Select(x => new
{
ComplaintID = x.ComplaintID,
CustomerName = x.Customer.Name,
CustomerAddress = x.Customer.Address,
MemberName = x.Member != null ? x.Member.Name: string.Empty,
AllocationName = x.Allocation != null ? x.Allocation.Name: string.Empty,
CategoryName = x.Category != null ? x.Category.Ssl_Name : string.Empty,
Stage1Start = x.Stage1StartDate,
Stage1Expiry = x.Stage1_ExpiryDate,
Stage2Start = x.Stage2StartDate,
Stage2Expiry = x.Stage2_ExpiryDate
});
.DefaultIfEmpty()
: यह केवल तब प्रभावित करता है जब db.Complains
खाली होता है। db.Complains.Where(...).OrderBy(...).Select(x => new { ..., MemberName = x.Member != null ? x.Member.Name : string.Empty, ... })
, बिना किसी के .DefaultIfEmpty()
, पहले से ही लेफ्ट जॉइन करेगा (यह मानते हुए कि Member
संपत्ति वैकल्पिक है)।
अगर UserGroups का UserGroupPrices तालिका के साथ कई संबंध है, तो EF में, एक बार संबंध को कोड में परिभाषित किया गया है:
//In UserGroups Model
public List<UserGroupPrices> UserGrpPriceList {get;set;}
//In UserGroupPrices model
public UserGroups UserGrps {get;set;}
आप बस इसके द्वारा सेट किए गए बाएं सम्मिलित परिणाम को खींच सकते हैं:
var list = db.UserGroupDbSet.ToList();
बाईं तालिका के लिए अपने DbSet को संभालने के लिए UserGroupDbSet है, जिसमें UserGrpPriceList शामिल होगा, जो दाईं तालिका से सभी संबद्ध रिकॉर्ड की एक सूची है।