एक बार जब हम अपने डेटाअलेयर को संग्रहीत प्रक्रियाओं में स्थानांतरित करने का निर्णय लेते हैं, और ये प्रक्रिया अक्सर कई जुड़े हुए परिणाम (उदाहरण के लिए नीचे) लौटाते हैं।
ठीक है, मेरा दृष्टिकोण लगभग समान है, लेकिन शायद थोड़ा अधिक आरामदायक है।
इस तरह आपका कोड दिख सकता है:
using ( var conn = GetConn() )
{
var res = await conn
.StoredProc<Person>( procName, procParams )
.Include<Book>( ( p, b ) => p.Books = b.Where( x => x.PersonId == p.Id ).ToList() )
.Include<Course>( ( p, c ) => p.Courses = c.Where( x => x.PersonId == p.Id ).ToList() )
.Include<Course, Mark>( ( c, m ) => c.Marks = m.Where( x => x.CourseId == c.Id ).ToList() )
.Execute();
}
चलो इसे तोड़ दो ...
एक्सटेंशन:
public static class SqlExtensions
{
public static StoredProcMapper<T> StoredProc<T>( this SqlConnection conn, string procName, object procParams )
{
return StoredProcMapper<T>
.Create( conn )
.Call( procName, procParams );
}
}
मैपर:
public class StoredProcMapper<T>
{
public static StoredProcMapper<T> Create( SqlConnection conn )
{
return new StoredProcMapper<T>( conn );
}
private List<MergeInfo> _merges = new List<MergeInfo>();
public SqlConnection Connection { get; }
public string ProcName { get; private set; }
public object Parameters { get; private set; }
private StoredProcMapper( SqlConnection conn )
{
Connection = conn;
_merges.Add( new MergeInfo( typeof( T ) ) );
}
public StoredProcMapper<T> Call( object procName, object parameters )
{
ProcName = procName.ToString();
Parameters = parameters;
return this;
}
public StoredProcMapper<T> Include<TChild>( MergeDelegate<T, TChild> mapper )
{
return Include<T, TChild>( mapper );
}
public StoredProcMapper<T> Include<TParent, TChild>( MergeDelegate<TParent, TChild> mapper )
{
_merges.Add( new MergeInfo<TParent, TChild>( mapper ) );
return this;
}
public async Task<List<T>> Execute()
{
if ( string.IsNullOrEmpty( ProcName ) )
throw new Exception( $"Procedure name not specified! Please use '{nameof(Call)}' method before '{nameof( Execute )}'" );
var gridReader = await Connection.QueryMultipleAsync(
ProcName, Parameters, commandType: CommandType.StoredProcedure );
foreach ( var merge in _merges )
{
merge.Result = gridReader
.Read( merge.Type )
.ToList();
}
foreach ( var merge in _merges )
{
if ( merge.ParentType == null )
continue;
var parentMerge = _merges.FirstOrDefault( x => x.Type == merge.ParentType );
if ( parentMerge == null )
throw new Exception( $"Wrong parent type '{merge.ParentType.FullName}' for type '{merge.Type.FullName}'." );
foreach ( var parent in parentMerge.Result )
{
merge.Merge( parent, merge.Result );
}
}
return _merges
.First()
.Result
.Cast<T>()
.ToList();
}
private class MergeInfo
{
public Type Type { get; }
public Type ParentType { get; }
public IEnumerable Result { get; set; }
public MergeInfo( Type type, Type parentType = null )
{
Type = type;
ParentType = parentType;
}
public void Merge( object parent, IEnumerable children )
{
MergeInternal( parent, children );
}
public virtual void MergeInternal( object parent, IEnumerable children )
{
}
}
private class MergeInfo<TParent, TChild> : MergeInfo
{
public MergeDelegate<TParent, TChild> Action { get; }
public MergeInfo( MergeDelegate<TParent, TChild> mergeAction )
: base( typeof( TChild ), typeof( TParent ) )
{
Action = mergeAction;
}
public override void MergeInternal( object parent, IEnumerable children )
{
Action( (TParent)parent, children.Cast<TChild>() );
}
}
public delegate void MergeDelegate<TParent, TChild>( TParent parent, IEnumerable<TChild> children );
}
यह सब है, लेकिन अगर आप त्वरित परीक्षण करना चाहते हैं, तो यहां आपके लिए मॉडल और प्रक्रिया है:
मॉडल:
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<Course> Courses { get; set; }
public List<Book> Books { get; set; }
public override string ToString() => Name;
}
public class Book
{
public Guid Id { get; set; }
public Guid PersonId { get; set; }
public string Name { get; set; }
public override string ToString() => Name;
}
public class Course
{
public Guid Id { get; set; }
public Guid PersonId { get; set; }
public string Name { get; set; }
public List<Mark> Marks { get; set; }
public override string ToString() => Name;
}
public class Mark
{
public Guid Id { get; set; }
public Guid CourseId { get; set; }
public int Value { get; set; }
public override string ToString() => Value.ToString();
}
सपा:
if exists (
select *
from sysobjects
where
id = object_id(N'dbo.MultiTest')
and ObjectProperty( id, N'IsProcedure' ) = 1 )
begin
drop procedure dbo.MultiTest
end
go
create procedure dbo.MultiTest
@PersonId UniqueIdentifier
as
begin
declare @tmpPersons table
(
Id UniqueIdentifier,
Name nvarchar(50)
);
declare @tmpBooks table
(
Id UniqueIdentifier,
PersonId UniqueIdentifier,
Name nvarchar(50)
)
declare @tmpCourses table
(
Id UniqueIdentifier,
PersonId UniqueIdentifier,
Name nvarchar(50)
)
declare @tmpMarks table
(
Id UniqueIdentifier,
CourseId UniqueIdentifier,
Value int
)
insert into @tmpPersons
values
( '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Иван' ),
( '467953a5-cb5f-4d06-9fad-505b3bba2058', N'Василий' ),
( '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'Алефтина' )
insert into @tmpBooks
values
( NewId(), '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Книга Математика' ),
( NewId(), '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Книга Физика' ),
( NewId(), '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Книга Геометрия' ),
( NewId(), '467953a5-cb5f-4d06-9fad-505b3bba2058', N'Книга Биология' ),
( NewId(), '467953a5-cb5f-4d06-9fad-505b3bba2058', N'Книга Химия' ),
( NewId(), '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'Книга История' ),
( NewId(), '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'Книга Литература' ),
( NewId(), '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'Книга Древне-шумерский диалект иврита' )
insert into @tmpCourses
values
( '30945b68-a6ef-4da8-9a35-d3b2845e7de3', '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Математика' ),
( '7881f090-ccd6-4fb9-a1e0-ff4ff5c18450', '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Физика' ),
( '92bbefd1-9fec-4dc7-bb58-986eadb105c8', '576fb8e8-41a2-43a9-8e77-a8213aa6e387', N'Геометрия' ),
( '923a2f0c-c5c7-4394-847c-c5028fe14711', '467953a5-cb5f-4d06-9fad-505b3bba2058', N'Биология' ),
( 'ace50388-eb05-4c46-82a9-5836cf0c988c', '467953a5-cb5f-4d06-9fad-505b3bba2058', N'Химия' ),
( '53ea69fb-6cc4-4a6f-82c2-0afbaa8cb410', '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'История' ),
( '7290c5f7-1000-4f44-a5f0-6a7cf8a8efab', '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'Литература' ),
( '73ac366d-c7c2-4480-9513-28c17967db1a', '52a719bf-6f1f-48ac-9e1f-4532cfc70d96', N'Древне-шумерский диалект иврита' )
insert into @tmpMarks
values
( NewId(), '30945b68-a6ef-4da8-9a35-d3b2845e7de3', 98 ),
( NewId(), '30945b68-a6ef-4da8-9a35-d3b2845e7de3', 87 ),
( NewId(), '30945b68-a6ef-4da8-9a35-d3b2845e7de3', 76 ),
( NewId(), '7881f090-ccd6-4fb9-a1e0-ff4ff5c18450', 89 ),
( NewId(), '7881f090-ccd6-4fb9-a1e0-ff4ff5c18450', 78 ),
( NewId(), '7881f090-ccd6-4fb9-a1e0-ff4ff5c18450', 67 ),
( NewId(), '92bbefd1-9fec-4dc7-bb58-986eadb105c8', 79 ),
( NewId(), '92bbefd1-9fec-4dc7-bb58-986eadb105c8', 68 ),
( NewId(), '92bbefd1-9fec-4dc7-bb58-986eadb105c8', 75 ),
( NewId(), '923a2f0c-c5c7-4394-847c-c5028fe14711', 198 ),
( NewId(), '923a2f0c-c5c7-4394-847c-c5028fe14711', 187 ),
( NewId(), '923a2f0c-c5c7-4394-847c-c5028fe14711', 176 ),
( NewId(), 'ace50388-eb05-4c46-82a9-5836cf0c988c', 189 ),
( NewId(), 'ace50388-eb05-4c46-82a9-5836cf0c988c', 178 ),
( NewId(), 'ace50388-eb05-4c46-82a9-5836cf0c988c', 167 ),
( NewId(), '53ea69fb-6cc4-4a6f-82c2-0afbaa8cb410', 8 ),
( NewId(), '53ea69fb-6cc4-4a6f-82c2-0afbaa8cb410', 7 ),
( NewId(), '53ea69fb-6cc4-4a6f-82c2-0afbaa8cb410', 6 ),
( NewId(), '7290c5f7-1000-4f44-a5f0-6a7cf8a8efab', 9 ),
( NewId(), '7290c5f7-1000-4f44-a5f0-6a7cf8a8efab', 8 ),
( NewId(), '7290c5f7-1000-4f44-a5f0-6a7cf8a8efab', 7 ),
( NewId(), '73ac366d-c7c2-4480-9513-28c17967db1a', 9 ),
( NewId(), '73ac366d-c7c2-4480-9513-28c17967db1a', 8 ),
( NewId(), '73ac366d-c7c2-4480-9513-28c17967db1a', 5 )
select * from @tmpPersons
select * from @tmpBooks
select * from @tmpCourses
select * from @tmpMarks
end
go