मुझे कथन से अधिक का उपयोग करके एक ग्रिड/अद्वितीय पहचानकर्ता कॉलम के विरुद्ध एक खंड उत्पन्न करने की आवश्यकता है। मेरी समस्या यह है कि मुझे गतिशील रूप से क्वेरी उत्पन्न करनी है। मैं जो चाहता हूं उसका एक उदाहरण यहां दिया गया है:

myTable.Where(x => Guid.Empty.CompareTo(x.ADifferentGuidColumn) > 0)

जो इस एसक्यूएल को उत्पन्न करता है (मैं यहां एसक्यूएल प्राप्त करने के लिए LINQPad का उपयोग कर रहा हूं):

-- Region Parameters
DECLARE @p0 UniqueIdentifier = '00000000-0000-0000-0000-000000000000'
-- EndRegion
SELECT <columns...>
FROM [myTable] AS [t0]
WHERE (@p0 > [t0].[ADifferentGuidColumn])

यह वही है जो मेरे पास है। यह एक बहुत बड़ी सामान्य विधि में है जहां T पैरामीटर टेबल/डोमेन मॉडल ऑब्जेक्ट है। यह संकलित करता है, लेकिन startPointBody को The binary operator GreaterThan is not defined for the types 'System.Guid' and 'System.Guid'. कहते समय उड़ा देता है

Guid startPoint = Guid.NewGuid(); //actual value in real code...
IQueryable<T> set = context.Set<T>().AsQueryable();
var parameter = Expression.Parameter(typeof(T), "x");
//find primary key
IProperty primaryKey = context.Model.FindEntityType(typeof(T).FullName).FindPrimaryKey().Properties.FirstOrDefault();
//expression for column we're filtering
var startPointMember = Expression.Property(parameter, primaryKey.Name);
ConstantExpression startPointConstant = Expression.Constant(startPoint, startPoint.GetType());
var startPointBody = Expression.GreaterThan(startPointMember, startPointConstant);
var startPointWhereExpression = Expression.Lambda<Func<T, bool>>(startPointBody, parameter);
query = query.Where(startPointWhereExpression);

आप उदाहरण में देख सकते हैं कि मैं क्या चाहता हूं कि मैं वास्तव में Guid.CompareTo() का उपयोग कर रहा हूं, लेकिन मुझे नहीं पता कि इस गतिशील फैशन में इसे कैसे लिखना है। मैं उम्मीद कर रहा था कि मैं धोखा दे सकता हूं क्योंकि उत्पन्न एसक्यूएल सिर्फ एक साधारण > तुलना कर रहा है, लेकिन ईएफ ने मुझे पकड़ लिया।

1
Tim Coker 4 सितंबर 2019, 00:14

1 उत्तर

सबसे बढ़िया उत्तर

उदाहरण डेटा के साथ एक कार्यशील समाधान यहां दिया गया है। मैंने इसे डॉकर में स्थानीय एसक्यूएल सर्वर इंस्टेंस से जुड़े लिनकपैड में एक साथ रखा है।

यहाँ तालिका और डेटा है (कुछ गाइड डेमो कोड में हार्ड कोडित हैं):

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[test](
    [col1] [uniqueidentifier] NOT NULL,
    [col2] [uniqueidentifier] NOT NULL
) ON [PRIMARY]
GO

insert into test (col1,col2) values ('d3aaaf86-d4e5-4d77-897e-1b36c1100448', '09e0073a-be0e-405a-9564-d34056c8e42a')
insert into test (col1,col2) values ('d3aaaf86-d4e5-4d77-897e-1b36c1100448', 'a7a5aee0-87f4-42bb-90ac-dac7b52bffbf')
insert into test (col1,col2) values ('d3aaaf86-d4e5-4d77-897e-1b36c1100448', '104ab3c0-8521-453f-bf48-552358618a90')
insert into test (col1,col2) values ('d3aaaf86-d4e5-4d77-897e-1b36c1100448', '6128657b-5c84-4c95-afbf-4bfe06c2c7ea')
insert into test (col1,col2) values ('d3aaaf86-d4e5-4d77-897e-1b36c1100448', '96bc5a4f-0baf-44fb-a85c-fbddcca82ff9')
insert into test (col1,col2) values ('ac15b74b-593f-4d28-9f80-46cc84a89e79', 'db4621e0-b6fe-40ad-a4c5-601f875c5bbf')
insert into test (col1,col2) values ('a5071253-3a12-45c8-a495-d96bb56f49c9', 'a4536fa3-922a-43b0-a568-abfcf2daba9f')
insert into test (col1,col2) values ('a3cf9625-787a-4d91-a692-e2db8eb246a2', 'b7b7d1f9-b9cc-4201-bf75-40b0c4c2d301')

और यहां पूरा प्रोग्राम है जिसे आप LINQPad में चला सकते हैं:

void Main()
{
    Test<Test>();
}

static void Test<T>() where T : class
{
    PropertyInfo propertyInfo = typeof(T).GetProperty("col1");

    var parameter = Expression.Parameter(typeof(T), "x");

    //create where clause expression
    var orgIdMember = Expression.Property(parameter, "col1");
    ConstantExpression orgIdConstant = Expression.Constant(new Guid("d3aaaf86-d4e5-4d77-897e-1b36c1100448"), typeof(Guid));
    var orgIdBody = Expression.Equal(orgIdMember, orgIdConstant);
    var orgIdWhereExpression = Expression.Lambda<Func<Test, bool>>(orgIdBody, parameter); 

    TypedDataContext d = new TypedDataContext();

    var query = d.Tests.AsQueryable().Where(orgIdWhereExpression);

    //create start point expression 
    Guid startPoint = new Guid("09e0073a-be0e-405a-9564-d34056c8e42a");

    var startPointMember = Expression.Property(parameter, "col2");
    ConstantExpression startPointConstant = Expression.Constant(startPoint, startPoint.GetType());
    var left = Expression.Call(startPointMember, typeof(Guid).GetMethod("CompareTo", new Type[] { typeof(Guid) }), startPointConstant);
    var right = Expression.Constant(1);
    var startPointBody = Expression.Equal(left, right);
    var startPointWhereExpression = Expression.Lambda<Func<Test, bool>>(startPointBody, parameter);
    query = query.Where(startPointWhereExpression);

    MemberExpression keyMember = Expression.Property(parameter, "col1");
    var keyExpression = Expression.Lambda<Func<Test, Guid>>(keyMember, parameter);
    query = query.OrderBy(keyExpression);

    query.ToList().Dump();
}

यहाँ बहुत सारी अतिरिक्त बकवास है, लेकिन मेरे प्रश्न का वास्तविक उत्तर वह है जहाँ मैं left चर और उसके बाद की 4 पंक्तियों को परिभाषित करता हूँ। मैंने यह सब LINQPad में इसकी SQL सुविधा के कारण किया है, जो इस SQL ​​को आउटपुट के रूप में दिखाता है:

-- Region Parameters
DECLARE @p0 UniqueIdentifier = '09e0073a-be0e-405a-9564-d34056c8e42a'
DECLARE @p1 UniqueIdentifier = 'd3aaaf86-d4e5-4d77-897e-1b36c1100448'
-- EndRegion
SELECT [t0].[col1] AS [Col1], [t0].[col2] AS [Col2]
FROM [test] AS [t0]
WHERE ([t0].[col2] > @p0) AND ([t0].[col1] = @p1)
ORDER BY [t0].[col1]

संपादित करें: ऐसा प्रतीत होता है कि मैं starPointWhereExpression के साथ क्या करने की कोशिश कर रहा हूं जैसे अभिव्यक्ति बनाते समय ईएफ कोर के क्वेरी जेनरेटर में एक बग/कमी है। मेरे परीक्षण में, ऐसा लगता है कि जब यह उस अभिव्यक्ति तक पहुंच जाता है, तो यह छोड़ देता है और सर्वर के खिलाफ जो कुछ भी है उसे निष्पादित करने का प्रयास करता है और स्थानीय प्रसंस्करण के लिए आगे की अभिव्यक्ति बचाता है। मैं ऐसा इसलिए कह रहा हूं क्योंकि जहां यह कोड चल रहा है, वहां मैं Skip() और Take() एक्सप्रेशन जोड़ता हूं। जब गाइड्स की तुलना करने वाला एक्सप्रेशन पाइपलाइन में होता है, तो स्किप और टेक स्टेटमेंट जेनरेट किए गए SQL में नहीं होते हैं। अगर मैं इसे पाइपलाइन में नहीं जोड़ता, तो वे कथन इसे जेनरेट किए गए SQL में बनाते हैं।

संपादित करें 2: मैंने इसके बारे में एक बग github पर दर्ज किया। इसे ईएफ कोर 3 में संबोधित किया जाएगा। इस लेखन के रूप में (ईएफ कोर 3 पूर्वावलोकन 9 के खिलाफ परीक्षण किया गया), जेनरेट किया गया एसक्यूएल निश्चित रूप से अजीब है और कुछ काम का उपयोग कर सकता है।

0
Tim Coker 5 सितंबर 2019, 03:57