update object

Jun 11, 2015 at 6:16 AM
Edited Jun 11, 2015 at 6:16 AM
I try to modify an object but the properties of object is not save into the db. Why ?


TennisMatch tennisMatch = await _gameDal.GetEntityAsync<TennisMatch>(p => p.ID == id);
        if (tennisMatch == null)
        {
            return NotFound();
        }

        TennisManager.StartTennisMatch(tennisMatch); //change status property of tennisGame
          await _gameDal.SaveAsync();
Coordinator
Jun 11, 2015 at 11:10 AM
Is this with MongoDb or entity framework?
Jun 11, 2015 at 5:03 PM
Edited Jun 11, 2015 at 5:04 PM
Entityframework
__

public class T__ennisMatch
: BaseInfo
{
    public Int64 OwnerId { get; set; }
    public Int64 _HomeTeamId { get; set; }
    public Int64 _VisitorTeamId { get; set; }
    public BestOf bestOf { get; set; }
    public bool Auto { get; set; }
    public virtual List<TennisSet> Sets { get; set; }
    public TennisMatch(Int64 HomeTeamID, Int64 VisitorTeamID, Int64 ownerID, BestOf bestOf, bool auto=true)
    {
        this.DateCreated = DateTime.UtcNow;
        this.GameStatus = GameStatus.Created;
        this.HomeScore = 0;
        this.VisitorScore = 0;
        this.OwnerId = ownerID;
        this._HomeTeamId = HomeTeamID;
        this._VisitorTeamId = VisitorTeamID;
        this.bestOf = bestOf;
        this.Auto = auto;
        this.Sets = new List<TennisSet>();
    }
    public TennisMatch()
    { }

}
public class BaseInfo
{
    [Key]
    public Int64 ID { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime? DateStarted { get; set; }
    public DateTime? DateFinished { get; set; }
    public GameStatus GameStatus { get; set; }
    public Int64 HomeScore { get; set; }
    public Int64 VisitorScore { get; set; }
    public Nullable<Int64> WinnerTeamId { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }

    public BaseInfo()
    {
        DateCreated = DateTime.Now;
        DateStarted = null;
        GameStatus = GameStatus.Created;
    }
}
TennisManager.StartTennisMatch
public static void StartTennisMatch(TennisMatch tennisMatch)
    {
        tennisMatch.DateStarted = DateTime.UtcNow;
        tennisMatch.GameStatus = GameStatus.Playing;
    }
Coordinator
Jun 12, 2015 at 10:55 AM
Your code looks fine.

Have you disabled proxy generation as EF can't track entity changes when proxies aren't generated. If you have you have to you need to add the following line of code before you save your entity:

_gameDal.Modify(tennisMatch) or _await gameDal.ModifyAsync(tennisMatch) .

This basic tells the EF context that it should update this entity when save is called.
Jun 15, 2015 at 10:34 PM
Where I see if I disabled proxy generation ? Normaly i don't desactivate if is default value.

When I try to call _gameDal.Modify(tennisMatch), I have an error.

System.InvalidOperationException: Attaching an entity of type 'DudesStudio.DudesSportNetwork.WebApi.Modules.Game.Models.TennisMatch' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
StackTrace de résultat  :
à System.Data.Entity.Core.Objects.ObjectContext.VerifyRootForAdd(Boolean doAttach, String entitySetName, IEntityWrapper wrappedEntity, EntityEntry existingEntry, EntitySet& entitySet, Boolean& isNoOperation)
à System.Data.Entity.Core.Objects.ObjectContext.AttachTo(String entitySetName, Object entity)
à System.Data.Entity.Internal.Linq.InternalSet1.<>c__DisplayClassa.<Attach>b__9()
à System.Data.Entity.Internal.Linq.InternalSet
1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
à System.Data.Entity.Internal.Linq.InternalSet1.Attach(Object entity)
à System.Data.Entity.Internal.InternalEntityEntry.set_State(EntityState value)
à NRepository.EntityFramework.EntityFrameworkCommandRepository.<Modify>b__2[T](T p)
à NRepository.Core.Command.DefaultModifyCommandInterceptor.Modify[T](ICommandRepository repository, Action
1 modifyAction, T entity)
à NRepository.EntityFramework.EntityFrameworkCommandRepository.Modify[T](T entity)
à NRepository.Core.RepositoryBase.Modify[T](T entity)
à NRepository.Core.RepositoryBase.<>c__DisplayClassa61.<ModifyAsync>b__a5()
à System.Threading.Tasks.Task.InnerInvoke()
à System.Threading.Tasks.Task.Execute()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
à System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
à NRepository.Core.RepositoryBase.<ModifyAsync>d__a8
1.MoveNext()
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
à System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
à System.Runtime.CompilerServices.TaskAwaiter.GetResult()
à DudesStudio.DudesSportNetwork.WebApi.Modules.Game.Controllers.TennisController.<StartTennisMatch>d__5.MoveNext() dans c:\DEV\Dudes\DudesSportNetwork\DudesStudio.DudesSportNetwork.WebApi\Modules\Game\Controllers\TennisController.cs:ligne 64
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
à System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
à System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
à DudesStudio.DudesSportNetwork.WebApi.Tests.Modules.Game.TennisGamesControllerTest.<StartTennisMatchTest>d__6.MoveNext() dans c:\DEV\Dudes\DudesSportNetwork\DudesStudio.DudesSportNetwork.WebApi.Tests\Modules\Game\TennisGamesControllerTest.cs:ligne 100
--- Fin de la trace de la pile à partir de l'emplacement précédent au niveau duquel l'exception a été levée ---
à System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
à System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
à System.Runtime.CompilerServices.TaskAwaiter.GetResult()

it's normal to have a same primary keay values because i try to make an update.

Thanks for your help
Jun 15, 2015 at 11:07 PM
Edited Jun 15, 2015 at 11:09 PM
Other information

var container = new UnityContainer();
        //ENTITYFRAMEWORK
        container.RegisterType<GameDal>(new InjectionConstructor(
               new EntityFrameworkQueryRepository(new GameContext()), new EntityFrameworkCommandRepository(new GameContext(), new DefaultRepositoryInterceptors())));


        GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);


public class GameDal : RepositoryBase
{
    public GameDal(IQueryRepository iQueryRepository, ICommandRepository iCommandRepository)
        : base(iQueryRepository, iCommandRepository)
    {
    }
}
public class TennisController : ApiController
{

    private GameDal _gameDal;
    public TennisController(GameDal gameDal)
    {
        this._gameDal = gameDal;
    }
}
Coordinator
Jun 16, 2015 at 11:12 AM
The problem you have is that your GamDal repository is using 2 different DbContexts - one for querying the data and one for writing the data. For your code to work you should only have a single DbContext per . Also you don't really need the GameDal class as you can use the IRepository (the Data access layer interface) directly in your service.

Try the following code:
// Unity configuration
container.RegisterType<IRepository, EntityFrameworkRepository>(new InjectionConstructor(typeof(GameContext)));

// Your web api controller
public class TennisController : ApiController
{

    private IRepository _gameDal;
    public TennisController(IRepository gameDal)
    {
        this._gameDal = gameDal;
    }
}
You now shouldn't need to add the Modify method either.
Jun 16, 2015 at 10:57 PM
I try this solution and it's work fine but the problem that i have with this solution for me is I use in t__he same project many dbcontext that i use entityframework provider and other use mongodb provider.__ If i use container.RegisterType<IRepository, EntityFrameworkRepository>(new InjectionConstructor(typeof(GameContext)));. All IRepository use only the gameContext. But for my newsletters module, i want that the IRepository use newsletterdbcontext.

I know is possible for me to put all module in separate project but is more ease for me right now to have only 1 project with many db context.

Do you have a solution for that ?


public void ConfigureContainer(IAppBuilder app)
    {
        var container = new UnityContainer();

        #region "Newsletter"
        //ENTITYFRAMEWORK
        container.RegisterType<NewsletterDal>(new InjectionConstructor(
                new EntityFrameworkQueryRepository(new NewsletterContext()), new EntityFrameworkCommandRepository(new NewsletterContext(), new DefaultRepositoryInterceptors())));

        #endregion
        #region "Game"
        //ENTITYFRAMEWORK
        container.RegisterType<GameDal>(new InjectionConstructor(
               new EntityFrameworkQueryRepository(new GameContext()), new EntityFrameworkCommandRepository(new GameContext(), new DefaultRepositoryInterceptors())));

        #endregion

        GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);



    }
Thanks
Coordinator
Jun 17, 2015 at 11:20 AM
Edited Jun 17, 2015 at 11:42 AM
You need to use named dependencies :
// *******  Unity Configuration ******

// Rather than hard coded strings as below, best to use constants
// public const string GameRepositoryDependency = "GameRepository";
// public const string NewsletterRepositoryDependency = "NewsletterRepository";

// newsletter
container.RegisterType<IRepository, EntityFrameworkRepository>(
   "NewsletterRepository",
    new InjectionConstructor(typeof(NewsletterContext)));

// Game Context
container.RegisterType<IRepository, EntityFrameworkRepository>(
   "GameRepository",
    new InjectionConstructor(typeof(GameContext)));
Then you can either add extra mapping in your configuration for each controller:
container.RegisterType<TennisController>(
    new InjectionConstructor(                             
        new ResolvedParameter<IRepository>("GameRepository") // IRepository resolved to "GameRepository"
    )
);
Or define which resolver to use directly in your controller via attributes:
public class TennisController : ApiController
{
    private IRepository _gameDal;
    public TennisController([Dependency("GameRepository")] IRepository gameDal)
    {
        this._gameDal = gameDal;
    }
}
Using this method you should be able to delete your NewsletterDal & GameDal classes plus you can even add mutiple IRepository parameters to a single constructor each using different db contexts or implementations (EF & Mongo) .
Jun 17, 2015 at 5:40 PM
It's works thanks