2017-09-24 3 views
0

J'ai obtenu mon code fonctionne très bien, mais je ne suis pas vraiment sûr si l'approche que j'ai prise est une meilleure pratique ou non. Donc, j'ai décidé de demander dans ce forum à la place.Insérer ou mettre à jour les données du modèle mappé dans la base de données

Voici donc ma situation:

Je suis mon modèle qui ressemble à ceci:

public class Member 
{ 
    [Range(1, int.MaxValue)] 
    public int? MemberID { get; set; } 

    [Required] 
    public List<MemberExperience> MemberExperiences { get; set; } 

    [Required] 
    public string MemberAddress { get; set; } 

    [Required] 
    public MemberInformation MemberInformation { get; set; } 
} 

public class MemberExperience 
{ 
    [Required] 
    [Range(1, int.MaxValue)] 
    public int FromYear { get; set; } 

    [Required] 
    [Range(1, int.MaxValue)] 
    public int ToYear { get; set; } 

    [Required] 
    public string CompanyAddress { get; set; } 

    [Required] 
    public string ProgrammingLanguage { get; set; } 
} 

public class MemberInformation 
{ 
    [Required] 
    public string FullName { get; set; } 

    [Required] 
    public DateTime BirthDate { get; set; } 

    [Required] 
    public string TelephoneNumber { get; set; } 
} 

Et du côté client, ce que je passe au serveur est comme ceci:

{ 
    "MemberExperiences": [ 
    { 
     "FromYear": 2005, 
     "ToYear": 2008, 
     "CompanyAddress": "string", 
     "ProgrammingLanguage": "Javascript" 
    }, 
    { 
     "FromYear": 2009, 
     "ToYear": 2012, 
     "CompanyAddress": "string", 
     "ProgrammingLanguage": "C++" 
    }, 
    { 
     "FromYear": 2013, 
     "ToYear": 2017, 
     "CompanyAddress": "string", 
     "ProgrammingLanguage": "C#" 
    } 
    ], 
    "MemberAddress": "string", 
    "MemberInformation": { 
     "FullName": "string", 
     "BirthDate": "1992-01-01", 
     "TelephoneNumber": "string" 
    } 
} 

Puis mon contrôleur ressemblait à ceci (les données que je veux passer du côté client, seront converties en Member modèle qui ont toutes les données dedans):

[HttpPost] 
public HttpActionResult AddMember([FromBody] Member member) 
{ 
     var response = AddMemberToDatabase(member); 

     return Ok(response); 
} 

Mais, puisque je ne savais pas comment Dapper (j'utilise Dapper pour la communication à la base de données) convertir la variable cartographiée (dans ce cas MemberExperience et MemberInformation) en objet unique et d'être reconnu. Donc, ce que je faisais est comme ceci:

  1. Prenez toutes les données membres, mais avant l'insérer dans la base de données, je vais faire une classe stockée la liste des données de MemberExperience et MemberInformation.

  2. Joignez toutes les données dans une seule longue chaîne avec un séparateur séparé que seule la base de données permet d'y accéder et le connaît.

SingleMember Classe:

public class SingleMember 
{ 
    public int? MemberID { get; set; } 
    public string FromYears { get; set; } 
    public string ToYears { get; set; } 
    public string CompanyAddresses { get; set; } 
    public string ProgrammingLanguages { get; set; } 
    public string MemberAddress { get; set; } 
    public string FullName { get; set; } 
    public DateTime BirthDate { get; set; } 
    public string TelephoneNumber { get; set; } 
} 

fonction AddMemberToDatabase:

private int AddMemberToDatabase(Member members) 
{ 
    var separator = "$Format"; 

    var singleMember = new SingleMember 
    { 
     FromYears = string.Join(separator, members.MemberExperiences.Select(x => x.FromYear)), 
     ToYears = string.Join(separator, members.MemberExperiences.Select(x => x.ToYear)), 
     CompanyAddresses = string.Join(separator, members.MemberExperiences.Select(x => x.CompanyAddress)), 
     ProgrammingLanguages = string.Join(separator, members.MemberExperiences.Select(x => x.ProgrammingLanguage)), 
     MemberAddress = members.MemberAddress; 
     FullName = members.MemberInformation.FullName; 
     BirthDate = members.MemberInformation.BirthDate; 
     TelephoneNumber = members.MemberInformation.TelephoneNumber; 
    }; 

    using (TransactionScope trans = new TransactionScope()) 
    using (IDbConnection conn = new SqlConnection("MyConnection")) 
    { 
     conn.Open(); 

     int rowsAffected = conn.Execute("MyStoredProcedure", singleMember); 

     trans.Complete(); 

     return rowsAffected; 
    } 
} 

Puis, à partir du MyStoredProcedure, il partagera les données jointes par le format défini $Format et insérez-le dans le tableau 1 par 1 jusqu'à ce que l'élément qui est en train d'être divisé n o plus à gauche d'être divisé.

ALTER PROCEDURE [dbo].[MyStoredProcedure] 
(
    @FromYears    NVARCHAR(MAX), // will be 2005$Format2009$Format2013 
    @ToYears    NVARCHAR(MAX), // will be 2008$Format2012$Format2017 
    @CompanyAddresses  NVARCHAR(MAX), // will be string$Formatstring$Formatstring 
    @ProgrammingLanguages NVARCHAR(MAX), // will be Javascript$FormatC++$FormatC# 
    @MemberAddress   NVARCHAR(MAX), 
    @FullName    NVARCHAR(MAX), 
    @BirthDate    DATETIME, 
    @TelephoneNumber  NVARCHAR(MAX) 
) 
AS 
BEGIN 
    DECLARE 
     @MemberCount   INT, 
     @FromYear    INT, 
     @ToYear     INT, 
     @CompanyAddress   NVARCHAR(MAX), 
     @ProgrammingLanguage NVARCHAR(MAX) 

    DECLARE @FromYearTable  TABLE (
     [ID]   INT   IDENTITY, 
     [FromYear]  INT   NOT NULL 
    ) 

    DECLARE @ToYearTable  TABLE (
     [ID]   INT   IDENTITY, 
     [ToYear]  INT   NOT NULL 
    ) 

    DECLARE @CompanyAddressTable  TABLE (
     [ID]    INT    IDENTITY, 
     [CompanyAddress] NVARCHAR(MAX) NOT NULL 
    ) 

    DECLARE @ProgrammingLanguageTable   TABLE (
     [ID]     INT    IDENTITY, 
     [ProgrammingLanguage] NVARCHAR(MAX) NOT NULL 
    ) 

    DECLARE @MemberTable   TABLE (
     [ID]     INT    IDENTITY, 
     [FromYear]    INT    NOT NULL, 
     [ToYear]    INT    NOT NULL, 
     [CompanyAddress]  NVARCHAR(MAX) NOT NULL, 
     [ProgrammingLanguage] NVARCHAR(MAX) NOT NULL 
    ) 

    INSERT INTO @FromYearTable 
    SELECT [SplittedItem] FROM [StringSplit] (@FromYears, '$Format') 

    INSERT INTO @ToYearTable 
    SELECT [SplittedItem] FROM [StringSplit] (@ToYears, '$Format') 

    INSERT INTO @CompanyAddressTable 
    SELECT [SplittedItem] FROM [StringSplit] (@CompanyAddresses, '$Format') 

    INSERT INTO @ProgrammingLanguageTable 
    SELECT [SplittedItem] FROM [StringSplit] (@ProgrammingLanguages, '$Format') 

    INSERT INTO @MemberTable 
    SELECT a.[FromYear], b.[ToYear], c.[CompanyAddress], d.[ProgrammingLanguage] 
    FROM @FromYearTable a 
    INNER JOIN @ToYearTable b ON a.[ID] = b.[ID] 
    INNER JOIN @CompanyAddressTable c ON a.[ID] = c.[ID] 
    INNER JOIN @ProgrammingLanguageTable d ON a.[ID] = d.[ID] 

    /* 
     Will be like: 
     ID FromYear ToYear CompanyAddress ProgrammingLanguage 
     1 2005  2008 string   Javascript 
     2 2009  2012 string   C++ 
     3 2013  2017 string   C# 
    */ 

    SET @MemberCount = (SELECT COUNT(*) FROM @MemberTable) 

    WHILE (@MemberCount > 0) 
    BEGIN 
     SET @FromYear = (SELECT TOP 1 [FromYear] FROM @MemberTable WHERE [ID] = @MemberCount) 
     SET @ToYear = (SELECT TOP 1 [ToYear] FROM @MemberTable WHERE [ID] = @MemberCount) 
     SET @CompanyAddress = (SELECT TOP 1 [CompanyAddress] FROM @MemberTable WHERE [ID] = @MemberCount) 
     SET @ProgrammingLanguage = (SELECT TOP 1 [ProgrammingLanguage] FROM @MemberTable WHERE [ID] = @MemberCount) 

     INSERT INTO [MyTable] (@FromYear, @ToYear, @CompanyAddress, @ProgrammingLanguage, @MemberAddress, @FullName, @BirthDate, @TelephoneNumber) 

     SET @MemberCount -= 1 
    END 
END 

Y a-t-il une meilleure façon de procéder?

Votre réponse a été très appréciée.

Merci

+0

Comment les données sont-elles mappées dans la base de données? Combien de tables stockez-vous des données? Pouvez-vous fournir quelques détails à ce sujet aussi? –

+0

Salut @PiyushKhanna, s'il vous plaît voir la question mise à jour ci-dessus, j'ai inclus la procédure stockée ainsi. Merci – Reinhardt

Répondre

0

je pense que ce n'est pas efficace de créer des procédures stockées pour les opérations CRUD. Si vous avez beaucoup de tables, créez un support C# dans votre application pour générer des commandes SQL (Insert, Update, Delete) et envoyez-les dans la transaction (TransactionScope) - en tant que SqlCommand avec les paramètres - dans la base de données.

+0

Salut @bmi, et si j'ai plus de 1 besoin d'être inséré dans la base de données?devrais-je faire la boucle for à la place et exécuter l'opération CRUD 1 par 1 par heure, au lieu d'envoyer un tas de données dans la base de données, et laisser la base de données pour la boucle? Merci – Reinhardt

+0

Il n'y a pas de raison d'envoyer des commandes sql dans la boucle for (sauf une grande quantité de commandes sql - ceci peut être résolu par la commande bulk sql). Mais dans les systèmes compliqués peuvent être exécutés des exécutions séparées de commandes sql - cela n'a pas d'importance - mais cela augmente légèrement le trafic sql. Tout ce que vous pouvez exécuter en tant que commande d'un sql (toutes les insertions, mises à jour, suppressions) s'exécute à la fois. – bmi