none
WCF Data Service and Linq To SQL (Associations) RRS feed

  • Pergunta

  • Olá,

    Estou usando no meu projeto o WCF Data Service com Linq To SQL. Nele tenho duas tabelas GruposDeUsuario e Usuarios, quando eu insiro um usuário e defino o grupo (foreing key), no SaveChanges() aparece uma exceção: "An error occurred while processing this request".

    Eu setei o grupo pela associação do usuário que existe no Linq To "GrupoDeUsuarios". Eu tentei definir somente o GrupoID que fica na tabela Usuarios e funcionou, mas tem algum jeito de setar por essa associação, pois antes de começar usar o WCF este jeito funcionava, e grande parte do meu projeto está assim. Com essa associação eu mostrava o nome do grupo de usuário, ou alguma outra informação sem precisar fazer um select.

    Obrigado
    terça-feira, 6 de julho de 2010 18:46

Respostas

Todas as Respostas

    • Marcado como Resposta Thiago.Policarpo terça-feira, 3 de agosto de 2010 12:18
    terça-feira, 6 de julho de 2010 19:31
    Moderador
  • Israel Aece,

     

    Eu tentei fazer de acordo com o link, só que não consegui. Acho que não entendi muito bem. Eu fiz uma nova classe "public partial class Users",  e coloquei o "public UserGroups[] RecuperarUserGroups()" (essa classe coloquei no projeto do WCF) e coloquei no DataClasses.designer.cs coloquei o IsReference=true:

    [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Users")]
    [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true )]
    public partial class Users : INotifyPropertyChanging, INotifyPropertyChanged
    {
     Só que o serviço não roda. Aparece esse erro.


    The IsReference setting for type 'WcfServiceFuturePMS.Users' is 'True', but the same setting for its parent class 'WcfServiceFuturePMS.BusinessEntityBase' is 'False'. Derived types must have the same value for IsReference as the base type. Change the setting on type 'WcfServiceFuturePMS.Users' to 'False', or on type 'WcfServiceFuturePMS.BusinessEntityBase' to 'True', or do not set IsReference explicitly.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.Runtime.Serialization.InvalidDataContractException: The IsReference setting for type 'WcfServiceFuturePMS.Users' is 'True', but the same setting for its parent class 'WcfServiceFuturePMS.BusinessEntityBase' is 'False'. Derived types must have the same value for IsReference as the base type. Change the setting on type 'WcfServiceFuturePMS.Users' to 'False', or on type 'WcfServiceFuturePMS.BusinessEntityBase' to 'True', or do not set IsReference explicitly.

    Source Error:

    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [InvalidDataContractException: The IsReference setting for type 'WcfServiceFuturePMS.Users' is 'True', but the same setting for its parent class 'WcfServiceFuturePMS.BusinessEntityBase' is 'False'. Derived types must have the same value for IsReference as the base type. Change the setting on type 'WcfServiceFuturePMS.Users' to 'False', or on type 'WcfServiceFuturePMS.BusinessEntityBase' to 'True', or do not set IsReference explicitly.]
       System.Runtime.Serialization.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type) +736692
       System.Runtime.Serialization.ClassDataContractCriticalHelper.EnsureIsReferenceImported(Type type) +1816435
       System.Runtime.Serialization.ClassDataContractCriticalHelper.ImportDataMembers() +46
       System.Runtime.Serialization.ClassDataContractCriticalHelper..ctor(Type type) +268
       System.Runtime.Serialization.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type) +407
       System.Runtime.Serialization.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type) +86
       System.Runtime.Serialization.XsdDataContractExporter.GetSchemaTypeName(Type type) +80
       System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.ValidateDataContractType(Type type) +27
       System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.CreatePartInfo(MessagePartDescription part, OperationFormatStyle style, DataContractSerializerOperationBehavior serializerFactory) +25
       System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.CreateMessageInfo(DataContractFormatAttribute dataContractFormatAttribute, MessageDescription messageDescription, DataContractSerializerOperationBehavior serializerFactory) +299
       System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter..ctor(OperationDescription description, DataContractFormatAttribute dataContractFormatAttribute, DataContractSerializerOperationBehavior serializerFactory) +435
       System.ServiceModel.Description.DataContractSerializerOperationBehavior.GetFormatter(OperationDescription operation, Boolean& formatRequest, Boolean& formatReply, Boolean isProxy) +220
       System.ServiceModel.Description.DataContractSerializerOperationBehavior.System.ServiceModel.Description.IOperationBehavior.ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch) +58
       System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription contract, ClientRuntime proxy, DispatchRuntime dispatch) +256
       System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +3793
       System.ServiceModel.ServiceHostBase.InitializeRuntime() +60
       System.ServiceModel.ServiceHostBase.OnBeginOpen() +27
       System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +50
       System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +318
       System.ServiceModel.Channels.CommunicationObject.Open() +36
       System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +184
       System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +615

    [ServiceActivationException: The service '/ServiceFuturePMS.svc' cannot be activated due to an exception during compilation.  The exception message is: The IsReference setting for type 'WcfServiceFuturePMS.Users' is 'True', but the same setting for its parent class 'WcfServiceFuturePMS.BusinessEntityBase' is 'False'. Derived types must have the same value for IsReference as the base type. Change the setting on type 'WcfServiceFuturePMS.Users' to 'False', or on type 'WcfServiceFuturePMS.BusinessEntityBase' to 'True', or do not set IsReference explicitly..]
       System.Runtime.AsyncResult.End(IAsyncResult result) +679246
       System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +190
       System.ServiceModel.Activation.HostedHttpRequestAsyncResult.ExecuteSynchronous(HttpApplication context, String routeServiceVirtualPath, Boolean flowContext, Boolean ensureWFService) +234
       System.ServiceModel.Activation.HttpModule.ProcessRequest(Object sender, EventArgs e) +355
       System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

    terça-feira, 6 de julho de 2010 21:48
  • Tenho também um outro jeito que estava fazendo e estava gravando os dados, porém ele duplicava o UserGroups na hora de salvar, tato para inserir quanto para alterar.

    Bem o Linq To Sql setei a serialização como Unidiretional, na associação das duas tabelas desabilitei o filho, e usei um código para criar o DataClasses.denigner.cs customizado, pois precisei tirar algumas linhas do código para o UserGroup do User vir preenchido. São essas:

    if ((this.serializing && (this._UserGroups.HasLoadedOrAssignedValue == false)))
       {
         return null;
       }

    Fiz o WCF com as classes Service e IService, porém ele esta duplicando o código depois que salva.

    IService:

        [OperationContract]
        List<Users> GetUsers();
    
        [OperationContract]
        bool SaveUsers(Users User);
    
        [OperationContract]
        bool DeleteUsers(Users User);


    Service:

     public bool SaveUsers(Users User)
        {
          bool Log = true;
          
          BaseModel.BeginTransaction();
    
          if (User.IsNew)
            {
              BaseModel.DB.Users.InsertOnSubmit(User);
            }
            else
            {
    
              ObjectExtensions.CopyFrom(User, BaseModel.DB.Users.Single(e => e.ID == User.ID));
    
            }
            try
            {
              try
              {
                BaseModel.DB.SubmitChanges(ConflictMode.ContinueOnConflict);
                try
                {
                  BaseModel.Commit();
                }
                catch (Exception ex)
                {
                  BaseModel.RollBack();
                  Log = false;
                }
              }
    
              catch (ChangeConflictException)
              {
                foreach (ObjectChangeConflict temp in BaseModel.DB.ChangeConflicts)
                {
                  temp.Resolve(RefreshMode.KeepCurrentValues);
                }
                Log = false;
              }
            }
            catch (Exception erro)
            {
              Log = false;
            }
          return Log;
        }

    No serviçe eu retorno a bool para saber se gravou ou não. O BaseModel é uma classe para instanciar o DataClassesDataContext uma só vez. E o ObjectExtensions.CopyFrom é uma classe que peguei na net para fazer o papel do Attach.

     

    ObjectExtensions :

      public static class ObjectExtensions 
      {
      
          public static void CopyFrom(this object origem, object destino) {
    
          // Verifica se os objetos sÆo do mesmo tipo
          if (origem.GetType() != destino.GetType())
            throw new InvalidCastException();
    
          // Carrega a lista de propriedades do objeto
          PropertyInfo[] propiedades = origem.GetType().GetProperties();
    
          foreach (var propriedade in propiedades) {
    
            // Verifica se a propriedade ‚ publica e se possui permissÆo de escrita
            if (propriedade.CanWrite && propriedade.PropertyType.IsPublic && propriedade.PropertyType.IsSerializable)
            {
    
              // Copia o valor do objeto de origem para o objeto de destino
              var valor = propriedade.GetValue(origem, null);
              propriedade.SetValue(destino, valor, null);
            }
          }
        }
      }

    Então não consegui descobrir o porque ele está duplicando.

    Obrigado

     

    quarta-feira, 7 de julho de 2010 13:14
  • Boas Thiago,

    Eu sugeri o post, porque o LINQ To SQL traz por padrão, a navegação bidirecional. Se você tem uma relação entre Usuários e Grupos, então o problema que estava ocorrendo, deve ser devido a isso. O que eu sugiro no post é definir a propriedade IsReference do DataContract na classe pai.


    http://www.israelaece.com
    quarta-feira, 7 de julho de 2010 17:09
    Moderador
  • Olá Israel,

    Este erro que estava dando eu descobri o que era. Só não consegui entender onde eu uso o "public Categoria[] RecuperarCategorias()".
    No meu caso eu criei o RecuperarGrupo, e coloquei na classe "public partial class Users", que seria uma classe de extenção da tabela Users.

    Ou eu uso este método no client memso?

    Obrigado

    quinta-feira, 8 de julho de 2010 15:17
  • Boas Thiago,

    Poderia explicar melhor? Não compreendi.
    http://www.israelaece.com
    segunda-feira, 12 de julho de 2010 12:38
    Moderador
  • Thiago,

    Novidades quanto a essa sua dúvida?


    André Alves de Lima
    Visite o meu site: http://andrealveslima.spaces.live.com
    Me siga no Twitter: @andrealveslima
    sexta-feira, 30 de julho de 2010 00:20
    Moderador
  • Boas Thiago,

    Veja se este artigo pode te ajudar em algo: http://www.israelaece.com/post/Usando-LINQ-To-SQL-com-WCF.aspx
    http://www.israelaece.com

     

    Olá, então estava com duvida onde usar o DataLoadOptions, mas pesquisando na net descobri que é no momento que faz o select para pegar os registros. Obrigado...

    • Marcado como Resposta Thiago.Policarpo terça-feira, 3 de agosto de 2010 12:18
    terça-feira, 3 de agosto de 2010 12:18