Pergunta

Eu tenho um problema muito grande e não consigo encontrar qualquer outra pessoa na internet que tem o meu problema. Espero que StackOverflow pode me ...

ajudar

Eu estou escrevendo uma aplicação ASP.NET MVC e eu estou usando o conceito Repositório com LINQ to SQL como meu armazenamento de dados. Tudo está funcionando muito bem no que diz respeito à seleção de linhas de pontos de vista. E prendendo restrições básicas de regras de negócios. No entanto, eu sou confrontado com um problema nos meus mapeamentos de procedimento armazenado para exclusões, inserções e atualizações. Deixe-me explicar:

Nosso DBA colocou um monte de trabalho para colocar a lógica de negócios em todos os nossos procedimentos armazenados para que eu não precisa se preocupar com isso no meu fim. Claro, eu fazer a validação básica, mas ele consegue a integridade dos dados e conflitantes restrições de data, etc ... O problema que estou enfrentando é que todos os procedimentos armazenados (e eu quero dizer todos) tem 5 parâmetros adicionais (6 para inserções ) que fornecem informações de volta para mim. A idéia é que quando algo quebra, posso alertar o usuário com as informações apropriadas do nosso banco de dados.

Por exemplo:

sp_AddCategory(
    @userID INT,
    @categoryName NVARCHAR(100),
    @isActive BIT,
    @errNumber INT OUTPUT,
    @errMessage NVARCHAR(1000) OUTPUT,
    @errDetailLogID INT OUTPUT,
    @sqlErrNumber INT OUTPUT,
    @sqlErrMessage NVARCHAR(1000) OUTPUT,
    @newRowID INT OUTPUT)

A partir do procedimento acima armazenado, os 3 primeiros parâmetros são os únicos parâmetros que são usados ??para "Criar" o registro Categoria. Os parâmetros restantes são usados ??simplesmente para me dizer o que aconteceu dentro do método. Se uma regra de negócio é quebrado dentro do procedimento armazenado, ele não usa de palavras-chave do SQL 'RAISEERROR' quando as regras de negócios estão quebrados. Em vez disso, ele fornece informações sobre a volta de erro me utilizando os parâmetros de saída. Ele faz isso para cada único procedimento armazenado em nosso banco de dados até mesmo a atualizações e exclusões. Todas as chamadas 'Get' são feitas usando exibições personalizadas. Eles foram todos testados e a idéia era fazer meu trabalho mais fácil uma vez que não tem que adicionar a lógica de negócios para prender todos os vários cenários para garantir a qualidade dos dados.

Como eu disse, eu estou usando LINQ to SQL, e eu estou agora confrontados com um problema. O problema é que a minha "Categoria" modelo de objeto simplesmente tem 4 propriedades nele: CódigoDaCategoria, NomeDaCategoria, UserId e isActive. Quando eu abri o designer para mapear começou minhas propriedades para a inserção, eu percebi que não há realmente nenhuma (fácil) maneira de me conta para os parâmetros adicionais a menos que eu adicioná-los ao meu objeto modelo.

Teoricamente o que eu gostaria de fazer é esta:

// note: Repository Methods
public void AddCategory(Category category)
{
    _dbContext.Categories.InsertOnSubmit(category);
}

public void Save()
{
    _dbContext.SubmitChanges();
}

E depois da minha aula de CategoryController eu simplesmente faça o seguinte:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
    var category = new Category();
    try 
    {
        UpdateModel(category); // simple validation here...

        _repository.AddCategory(category);
        _repository.Save(); // should get error here!!

        return RedirectToAction("Index");
    }
    catch
    {
        // manage friendly messages here somehow... (??)
        // ...

        return View(category);
    }
}

Qual é a melhor maneira de gerenciar isso usando LINQ to SQL? I (pessoalmente) não sinto que faz sentido para ter todas essas propriedades adicionais adicionadas a cada objeto modelo ... Por exemplo, o 'Get' nunca deveria ter erros e eu não quero que meus métodos de repositório voltar um tipo de objeto para chamadas de conseguir, mas aceitar outro tipo de objeto para chamadas CUD.

Update: Minha solução! (01 de dezembro de 2009)

Aqui está o que eu fiz para resolver o meu problema. Eu me livrei do meu método 'Save ()' em todos os meus repositórios. Em vez disso, eu adicionei um método de 'Update ()' para cada repositório e realmente comprometer os dados para o banco de dados em cada CUD (Criar / update / delete ou seja.) Chamada.

Eu sabia que cada procedimento armazenado teve os mesmos parâmetros, então eu criei uma classe para mantê-los:

public class MySprocArgs 
{
    private readonly string _methodName;
    public int? Number;
    public string Message;
    public int? ErrorLogId;
    public int? SqlErrorNumber;
    public string SqlErrorMessage;
    public int? NewRowId;

    public MySprocArgs(string methodName)
    {
        if (string.IsNullOrEmpty(methodName))
            throw new ArgumentNullException("methodName");

        _methodName = methodName;
    }

    public string MethodName
    {
        get { return _methodName; }
    }

}

Eu também criou um MySprocException que aceita os MySprocArgs nele do construtor:

public class MySprocException : ApplicationException
{

    private readonly MySprocArgs _args;
    public MySprocException(MySprocArgs args) : base(args.Message)
    {
       _args = args;
    }

    public int? ErrorNumber
    {
        get { return _args.Number; }
    }

    public string ErrorMessage
    {
        get { return _args.Message; }
    }

    public int? ErrorLogId
    {
        get { return _args.ErrorLogId; }
    }

    public int? SqlErrorNumber
    {
        get { return _args.SqlErrorNumber; }
    }

    public string SqlErrorMessage
    {
        get { return _args.SqlErrorMessage; }
    }
}

Agora, aqui é onde tudo vem junto ... Usando o exemplo que eu comecei com a minha investigação inicial, aqui é o que o 'AddCategory ()' método pode parecer:

public void AddCategory(Category category)
{
   var args = new MySprocArgs("AddCategory");
   var result = _dbContext.AddWidgetSproc(
                    category.CreatedByUserId,
                    category.Name,
                    category.IsActive,
                    ref args.Number, // <-- Notice use of 'args'
                    ref args.Message,
                    ref args.ErrorLogId,
                    ref args.SqlErrorNumber,
                    ref args.SqlErrorMessage,
                    ref args.NewRowId);

   if (result == -1)
      throw new MySprocException(args);
} 

Agora, do meu controlador, eu simplesmente faça o seguinte:

[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Category category)
    {
        if (!ModelState.IsValid)
        { 
            // manage friendly messages        
            return View(category);
        }

        _repository.AddCategory(category);
        return RedirectToAction("Index");

    } 
}

O truque para gerir o novo MySprocException é simplesmente prendê-lo usando o atributo HandleError e redirecionar o usuário para uma página que compreende a MySprocException.

Espero que isso ajude alguém. :)

Foi útil?

Solução

Eu não acredito que você pode adicionar os parâmetros de saída a qualquer de suas classes LINQ porque os parâmetros não persistem em qualquer tabela em seu banco de dados.

Mas você pode lidar com parâmetros de saída em LINQ da seguinte forma.

Adicione o procedimento armazenado (s) que você quer projectados para chamar à sua .dbml usando o designer.

Ligue para o seu procedimento armazenado em seu código

 using (YourDataContext context = new YourDataContext())
 {
    Nullable<int> errNumber = null;
    String errMessage = null;
    Nullable<int> errDetailLogID = null;
    Nullable<int> sqlErrNumber = null;
    String sqlErrMessage = null;
    Nullable<int> newRowID = null;
    Nullable<int> userID = 23;
    Nullable<bool> isActive=true;

    context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
 }

Outras dicas

I haven' tentei ainda, mas você pode olhar para este artigo, onde ele fala sobre procedimentos armazenados que os parâmetros de saída de retorno.

http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx

Basicamente arraste o procedimento armazenado em sua LINQ to SQL designer de então ele deve fazer o trabalho para você.

O dbContext.SubmitChanges(); irá funcionar apenas para a entidade FRAMEWORK.I sugerem Save, Update e trabalho irá apagar usando um único procedimento armazenado ou usando 3 procedimento diferente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top