I'm mainly looking at usage of Dapper, but in general, any comments relating SQL -> C# object mapping best practices would be appreciated.
I've got two super simple objects I'm working with:
public class Subcategory
{
public Guid Id { get; set; }
public Guid CategoryId { get; set; }
public string Name { get; set; }
}
public class Category
{
public Category()
{
Subcategories = new List<Subcategory>();
}
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<Subcategory> Subcategories { get; set; }
}
Id
for both of them is set by the db on insert via T-SQL's newsequentialid()
.
I'm writing repository classes for each of the objects that conform to the following interface (actually implemented via an abstract class):
public interface IMaintanceRepository<T> where T: class
{
Guid Create(T toCreate);
T Read(Guid id);
T Update(T toUpdate);
void Delete(Guid id);
}
Right now, I'm trying to write the Update
method in the Category
repository. I have the following written, but I'm not sure if it's the most performant Dapper code as written.
public override Category Update(Category toUpdate)
{
var deleteRemovedSubcategories = @"
DELETE FROM dbo.Subcategories
WHERE CategoryId = @Id
AND Id NOT IN @Ids";
var addNewSubcategories = @"
INSERT INTO dbo.Subcategories (CategoryId, Name)
VALUES (@CategoryId, @Name)";
var updateExistingSubcategories = @"
CREATE TABLE #subcategories (
Id uniqueidentifier NOT NULL,
CategoryId uniqueidentifier NOT NULL,
Name varchar(50) NOT NULL
);
INSERT INTO #subcategories VALUES (@Id, @CategoryId, @Name);
UPDATE s1
SET s1.CategoryId = s2.CategoryId, s1.Name = s2.Name
FROM dbo.Subcategories s1
INNER JOIN #subcategories s2
ON s1.Id = s2.Id;
DROP TABLE #subcategories;";
var updateCategory = @"
UPDATE dbo.Categories
SET Name = @Name
OUTPUT INSERTED.*
WHERE Id = @Id;
SELECT * FROM dbo.Subcategories WHERE CategoryId = @Id";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Execute(deleteRemovedSubcategories, new { Id = toUpdate.Id, Ids = toUpdate.Subcategories.Select(s => s.Id) });
connection.Execute(addNewSubcategories, toUpdate.Subcategories.Where(s => s.Id == Guid.Empty));
connection.Execute(updateExistingSubcategories, toUpdate.Subcategories);
using (var multi = connection.QueryMultiple(updateCategory, toUpdate))
{
var category = multi.ReadSingle<Category>();
category.Subcategories = multi.Read<Subcategory>().ToList();
return category;
}
}
}
Is there any suggested improvements to doing something like this?
deleteRemovedSubcategories
query would delete newSubcategory
-ies added viaaddNewSubcategories
. I'm not sure if my intuition about this is misplaced though. \$\endgroup\$ – C Smith Jan 8 '17 at 3:24VALUES (/* params */)
into a bulk-load statement, per their documentation. It's not just one row, confirmed via testing. \$\endgroup\$ – C Smith Jan 8 '17 at 18:42toUpdate.Subcategories
, which is anICollection<Subcategory>
per the class in the question. Dapper supposedly bulk-loads anything that implementsIEnumerable<T>
, which is what you'd want. \$\endgroup\$ – C Smith Jan 8 '17 at 18:57