मैं डैपर के साथ सम्मिलित प्रविष्टि और वापसी की पहचान कैसे करूं?


170

मैं डेटाबेस में एक प्रविष्टि कैसे करूँ और डैपर के साथ सम्मिलित पहचान लौटाऊँ?

मैंने कुछ इस तरह की कोशिश की है:

string sql = "DECLARE @ID int; " +
             "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +
             "SELECT @ID = SCOPE_IDENTITY()";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).First();

लेकिन यह काम नहीं किया।

@Marc Gravell धन्यवाद, उत्तर के लिए। मैंने आपके समाधान की कोशिश की है लेकिन, अभी भी एक ही अपवाद निशान नीचे है

System.InvalidCastException: Specified cast is not valid

at Dapper.SqlMapper.<QueryInternal>d__a`1.MoveNext() in (snip)\Dapper\SqlMapper.cs:line 610
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in (snip)\Dapper\SqlMapper.cs:line 538
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param) in (snip)\Dapper\SqlMapper.cs:line 456

जवाबों:


286

यदि आप उपयोग करते हैं तो यह इनपुट / आउटपुट पैरामीटर ( मूल्य सहित ) का समर्थन करता है , लेकिन इस मामले में सरल विकल्प बस है:RETURNDynamicParameters

var id = connection.QuerySingle<int>( @"
INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff);
SELECT CAST(SCOPE_IDENTITY() as int)", new { Stuff = mystuff});

ध्यान दें कि SQL सर्वर के अधिक हाल के संस्करणों पर आप OUTPUTक्लॉज का उपयोग कर सकते हैं :

var id = connection.QuerySingle<int>( @"
INSERT INTO [MyTable] ([Stuff])
OUTPUT INSERTED.Id
VALUES (@Stuff);", new { Stuff = mystuff});

11
@ppiotrowicz hmmm .... darn SCOPEIDENTITY लौटने वाली है numeric, एह? शायद अपने मूल कोड का उपयोग करें और select @id? (यह सिर्फ एक कलाकारों को जोड़ता है)। मैं यह सुनिश्चित करने के लिए एक नोट करूंगा कि यह भविष्य के डैपर बिल्ड में स्वचालित रूप से काम करता है। अब के लिए एक और विकल्प है select cast(SCOPE_IDENTITY() as int)- फिर से, थोड़ा बदसूरत। मैं इसे ठीक कर दूंगा।
मार्क Gravell

2
@MarcGravell: वाह! ग्रेट मार्क, यह एक अच्छा है! मुझे एहसास नहीं था कि scope_identityवापसी प्रकार है numeric(38,0)। +1 वास्तव में अच्छा लगता है। हालांकि यह वास्तव में नहीं है और मुझे यकीन है कि मैं केवल एक ही नहीं हूं।
रॉबर्ट कोरिटनिक

5
अरे, यह उत्तर एक पहचान मूल्य पाने के लिए नंबर एक हिट है जो एक डैपर क्वेरी से वापस आता है। आपने उल्लेख किया है कि किसी वस्तु से बंधते समय यह बहुत सुधार होता है; क्या आप इसे अभी संपादित और अपडेट कर सकते हैं कि आप यह कैसे करेंगे? मैंने आपके Nov26'12 टिप्पणी के पास github पर टेस्ट फ़ाइल में संशोधन की जाँच की, लेकिन सवाल से संबंधित कुछ भी नहीं देखा: / मेरी धारणा Query<foo>उस आवेषण मूल्यों के लिए है तो * जहाँ id = SCOPE_IDENTITY () है।

2
@Xerxes क्या आपको लगता है कि यह CQS का उल्लंघन करता है? CQS इस बारे में नहीं है कि SQL ऑपरेशन ग्रिड देता है या नहीं। यह एक आज्ञा, शुद्ध और सरल है। यह शब्द का उपयोग करने के बावजूद CQS शब्दों में एक प्रश्न नहीं है Query
मार्क Gravell

3
Nitpicky, लेकिन उपयोग करने के बजाय Queryऔर लौटाए गए संग्रह से पहला मान प्राप्त करते हैं, मुझे लगता ExecuteScalar<T>है कि इस मामले में अधिक समझ में आता है क्योंकि अधिकांश मूल्य सामान्य रूप से वापस आ जाता है।
पीटर मजीद

53

KB: 2019779 , " SCOPE_IDENTITY () और @@ पहचान" का उपयोग करते समय आपको गलत मान मिल सकता है, OUTPUT क्लॉज सबसे सुरक्षित तंत्र है:

string sql = @"
DECLARE @InsertedRows AS TABLE (Id int);
INSERT INTO [MyTable] ([Stuff]) OUTPUT Inserted.Id INTO @InsertedRows
VALUES (@Stuff);
SELECT Id FROM @InsertedRows";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

14
FYI करें, यह SCOPE_IDENTITY का उपयोग करने की तुलना में धीमा हो सकता है और अद्यतन # 5 से SQL Server 2008 R2 सर्विस पैक 1 में ठीक किया गया था
माइकल सिल्वर

2
@MichaelSilver क्या आप OUTPUT से पहले SCOPE_IDENTITY या @@ पहचान का उपयोग करने की सलाह देते हैं ? KB: 2019779 FIXED था ?
किकिनेट

1
@Kiquenet, अगर मैं एक DB के खिलाफ कोड लिख रहा था जो कि तय नहीं था, तो मैं शायद OUTPUT क्लॉज का उपयोग करूंगा बस यह सुनिश्चित करने के लिए कि यह अपेक्षा के अनुरूप काम करता है।
माइकल सिल्वर

1
@ एक एकल रिकॉर्ड डालने के लिए महान काम करता है लेकिन अगर मैं एक संग्रह में पास हो An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context
जाऊं

44

एक देर से जवाब, लेकिन यहां उन उत्तरों का एक विकल्पSCOPE_IDENTITY() है जो हमने समाप्त कर दिए थे: OUTPUT INSERTED

सम्मिलित ऑब्जेक्ट की केवल आईडी लौटाएं:

यह आपको सम्मिलित पंक्ति के सभी या कुछ विशेषताओं को प्राप्त करने की अनुमति देता है:

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)
                        OUTPUT INSERTED.[Id]
                        VALUES(@Username, @Phone, @Email);";

int newUserId = conn.QuerySingle<int>(insertUserSql,
                                new
                                {
                                    Username = "lorem ipsum",
                                    Phone = "555-123",
                                    Email = "lorem ipsum"
                                }, tran);

आईडी के साथ सम्मिलित वस्तु लौटें:

यदि आप चाहते हैं कि आप मिल सकते हैं Phoneऔर Emailया पूरी सम्मिलित पंक्ति:

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)
                        OUTPUT INSERTED.*
                        VALUES(@Username, @Phone, @Email);";

User newUser = conn.QuerySingle<User>(insertUserSql,
                                new
                                {
                                    Username = "lorem ipsum",
                                    Phone = "555-123",
                                    Email = "lorem ipsum"
                                }, tran);

इसके अलावा, इसके साथ आप डिलीट या अपडेट की गई पंक्तियों का डेटा वापस कर सकते हैं । यदि आप ट्रिगर का उपयोग कर रहे हैं तो सावधान रहें क्योंकि:

OUTPUT से लौटे कॉलम डेटा को प्रतिबिंबित करते हैं क्योंकि यह INSERT, UPDATE, या DELETE स्टेटमेंट के बाद पूरा हो गया है, लेकिन ट्रिगर निष्पादित होने से पहले।

ट्रिगर के INSTEAD के लिए, लौटे परिणाम उत्पन्न होते हैं जैसे कि INSERT, UPDATE, या DELETE वास्तव में हुआ था, भले ही ट्रिगर ऑपरेशन के परिणामस्वरूप कोई संशोधन न हो। यदि एक कथन जिसमें एक OUTPUT क्लॉज़ शामिल है, एक ट्रिगर के शरीर के अंदर उपयोग किया जाता है, तो OUTPUT के साथ जुड़े स्तंभ संदर्भों और DELETED तालिकाओं के साथ डुप्लिकेटिंग कॉलम संदर्भों से बचने के लिए तालिका उपनामों को ट्रिगर सम्मिलित और हटाए गए तालिकाओं को संदर्भित करने के लिए उपयोग किया जाना चाहिए।

डॉक्स में इस पर अधिक: लिंक


1
@Kiquenet TransactionScope ऑब्जेक्ट को क्वेरी के साथ उपयोग करने के लिए। और अधिक यहाँ पाया जा सकता है: dapper-tutorial.net/transaction और यहाँ: stackoverflow.com/questions/10363933/…
तदिजा बगरिएक

क्या हम 'QuerySingle <int>' के बजाय यहां 'ExecuteScalarAsync <int>' का उपयोग कर सकते हैं?
एलेमे

6

SCOPE_IDENTITY के दशमलव (38,0) होने के कारण आपको जो InvalidCastException मिल रहा है ।

आप इसे एक इंट के रूप में निम्नानुसार कास्टिंग करके वापस कर सकते हैं:

string sql = @"
INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff);
SELECT CAST(SCOPE_IDENTITY() AS INT)";

int id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

4

निश्चित नहीं है कि यह इसलिए था क्योंकि मैं SQL 2000 के खिलाफ काम कर रहा था या नहीं, लेकिन मुझे यह करने के लिए काम करना था।

string sql = "DECLARE @ID int; " +
             "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +
             "SET @ID = SCOPE_IDENTITY(); " +
             "SELECT @ID";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();

2
<Code> सेलेक्ट कास्ट (SCOPE_IDENTITY () as int) </ code> चुनें और इसे 2000 में भी काम करना चाहिए।
डेविड अलेउ

क्या आपने कोशिश की select cast(SCOPE_IDENTITY() as int)?
किकेनेट

1

आपके जीवन को आसान बनाने के लिए एक बेहतरीन पुस्तकालय है Dapper.Contrib.Extensions। इसे शामिल करने के बाद आप बस लिख सकते हैं:

public int Add(Transaction transaction)
{
        using (IDbConnection db = Connection)
        {
                return (int)db.Insert(transaction);
        }
}

0

यदि आप Dapper.SimpleSave का उपयोग कर रहे हैं:

 //no safety checks
 public static int Create<T>(object param)
    {
        using (SqlConnection conn = new SqlConnection(GetConnectionString()))
        {
            conn.Open();
            conn.Create<T>((T)param);
            return (int) (((T)param).GetType().GetProperties().Where(
                    x => x.CustomAttributes.Where(
                        y=>y.AttributeType.GetType() == typeof(Dapper.SimpleSave.PrimaryKeyAttribute).GetType()).Count()==1).First().GetValue(param));
        }
    }

Dapper.SimpleSave क्या है?
किनिकेत

@Kirquenet, मैंने Dapper, Dapper.SimpleCRUD, Dapper.SimpleCRUD.ModelGenerator, Dapper। मैंने उन्हें न्यूगेट आयात के माध्यम से जोड़ा। मैंने उन्हें अपनी साइट के लिए सभी DAO को मचान के लिए एक T4 टेम्पलेट के साथ जोड़ा। github.com/Paymentsense/Dapper.SimpleSave github.com/Paymentsense/Dapper.SimpleLoad
Lodlaiden
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.