diff --git a/lib/net45/ServiceStack.Common.dll b/lib/net45/ServiceStack.Common.dll index ef554e5b9..fbd0a1d4a 100644 Binary files a/lib/net45/ServiceStack.Common.dll and b/lib/net45/ServiceStack.Common.dll differ diff --git a/src/ServiceStack.OrmLite/OrmLiteWriteApi.cs b/src/ServiceStack.OrmLite/OrmLiteWriteApi.cs index bed1ccdc1..fb0c7b839 100644 --- a/src/ServiceStack.OrmLite/OrmLiteWriteApi.cs +++ b/src/ServiceStack.OrmLite/OrmLiteWriteApi.cs @@ -91,6 +91,24 @@ public static void InsertUsingDefaults(this IDbConnection dbConn, params T[] dbConn.Exec(dbCmd => dbCmd.InsertUsingDefaults(objs)); } + /// + /// Insert results from SELECT SqlExpression, use selectIdentity to retrieve the last insert AutoIncrement id (if any). E.g: + /// var id = db.InsertIntoSelect<Contact>(db.From<Person>().Select(x => new { x.Id, Surname == x.LastName })) + /// + public static long InsertIntoSelect(this IDbConnection dbConn, ISqlExpression query) + { + return dbConn.Exec(dbCmd => dbCmd.InsertIntoSelect(query, commandFilter: null)); + } + + /// + /// Insert results from SELECT SqlExpression, use selectIdentity to retrieve the last insert AutoIncrement id (if any). E.g: + /// var id = db.InsertIntoSelect<Contact>(db.From<Person>().Select(x => new { x.Id, Surname == x.LastName })) + /// + public static long InsertIntoSelect(this IDbConnection dbConn, ISqlExpression query, Action commandFilter) + { + return dbConn.Exec(dbCmd => dbCmd.InsertIntoSelect(query, commandFilter: commandFilter)); + } + /// /// Insert a collection of POCOs in a transaction. E.g: /// db.InsertAll(new[] { new Person { Id = 9, FirstName = "Biggie", LastName = "Smalls", Age = 24 } }) diff --git a/src/ServiceStack.OrmLite/OrmLiteWriteCommandExtensions.cs b/src/ServiceStack.OrmLite/OrmLiteWriteCommandExtensions.cs index 21948ce38..ecea8d529 100644 --- a/src/ServiceStack.OrmLite/OrmLiteWriteCommandExtensions.cs +++ b/src/ServiceStack.OrmLite/OrmLiteWriteCommandExtensions.cs @@ -689,6 +689,30 @@ internal static void Insert(this IDbCommand dbCmd, Action command dbCmd.InsertAll(objs: objs, commandFilter: commandFilter); } + internal static long InsertIntoSelect(this IDbCommand dbCmd, ISqlExpression query, Action commandFilter) + { + var dialectProvider = dbCmd.GetDialectProvider(); + + var sql = query.ToSelectStatement(); + var selectFields = query.GetUntypedSqlExpression() + .SelectExpression + .Substring("SELECT ".Length) + .ParseCommands(); + + var fieldsOrAliases = selectFields + .Map(x => x.Name.LastRightPart("AS").Trim().StripQuotes()); + + dialectProvider.PrepareParameterizedInsertStatement(dbCmd, insertFields: fieldsOrAliases); + + dbCmd.SetParameters(query.Params); + + dbCmd.CommandText = dbCmd.CommandText.LeftPart(")") + ")\n" + sql; + + commandFilter?.Invoke(dbCmd); //dbCmd.OnConflictInsert() needs to be applied before last insert id + + return dbCmd.ExecNonQuery(); + } + internal static void InsertAll(this IDbCommand dbCmd, IEnumerable objs, Action commandFilter) { IDbTransaction dbTrans = null; diff --git a/src/ServiceStack.OrmLite/ServiceStack.OrmLite.csproj b/src/ServiceStack.OrmLite/ServiceStack.OrmLite.csproj index 5ca76b491..4932fcdd1 100644 --- a/src/ServiceStack.OrmLite/ServiceStack.OrmLite.csproj +++ b/src/ServiceStack.OrmLite/ServiceStack.OrmLite.csproj @@ -56,4 +56,8 @@ + + + + diff --git a/tests/ServiceStack.OrmLite.Tests/OrmLiteInsertTests.cs b/tests/ServiceStack.OrmLite.Tests/OrmLiteInsertTests.cs index 9b80c9b0f..e79151817 100644 --- a/tests/ServiceStack.OrmLite.Tests/OrmLiteInsertTests.cs +++ b/tests/ServiceStack.OrmLite.Tests/OrmLiteInsertTests.cs @@ -375,6 +375,54 @@ public void Can_insert_record_with_Computed_column() fieldDef.IsComputed = true; } } + + [Test] + public void Can_InsertIntoSelect_using_Custom_Select() + { + using (var db = OpenDbConnection()) + { + OrmLiteConfig.BeforeExecFilter = cmd => cmd.GetDebugString().Print(); + db.DropAndCreateTable(); + db.DropAndCreateTable(); + + var userAuth = new UserAuth { + Id = 1, + UserName = "UserName", + Email = "a@b.com", + PrimaryEmail = "c@d.com", + FirstName = "FirstName", + LastName = "LastName", + DisplayName = "DisplayName", + Salt = "Salt", + PasswordHash = "PasswordHash", + CreatedDate = DateTime.Now, + ModifiedDate = DateTime.UtcNow, + }; + db.Insert(userAuth); + + var q = db.From() + .Where(x => x.UserName == "UserName") + .Select(x => new { + x.UserName, + x.Email, + GivenName = x.FirstName, + Surname = x.LastName, + FullName = x.FirstName + " " + x.LastName + }); + + var id = db.InsertIntoSelect(q); + Assert.That(id, Is.EqualTo(1)); + + var result = db.Select()[0]; + + Assert.That(result.Id, Is.GreaterThan(0)); + Assert.That(result.UserName, Is.EqualTo(userAuth.UserName)); + Assert.That(result.Email, Is.EqualTo(userAuth.Email)); + Assert.That(result.GivenName, Is.EqualTo(userAuth.FirstName)); + Assert.That(result.Surname, Is.EqualTo(userAuth.LastName)); + Assert.That(result.FullName, Is.EqualTo(userAuth.FirstName + " " + userAuth.LastName)); + } + } } public class Market @@ -458,4 +506,15 @@ public class UserAuthRole public virtual string RefIdStr { get; set; } public virtual Dictionary Meta { get; set; } } + + public class SubUserAuth + { + [AutoIncrement] + public virtual int Id { get; set; } + public virtual string UserName { get; set; } + public string Email { get; set; } + public string GivenName { get; set; } + public string Surname { get; set; } + public string FullName { get; set; } + } } \ No newline at end of file