EF Code First issue on CommitTransaction - using Repository pattern - repository-pattern

I am having an issue with EF 4.1 using "Code First". Let me setup my situation before I start posting any code. I have my DBContext class, called MemberSalesContext, in a class library project called Data.EF. I have my POCOs in a seperate class library project called Domain. My Domain project knows nothing of Entity Framework, no references, no nothing. My Data.EF project has a reference to the Domain project so that my DB context class can wire up everything in my mapping classes located in Data.EF.Mapping. I am doing all of the mappings in this namespace using the EntityTypeConfiguration class from EntityFramework. All of this is pretty standard stuff. On top of Entity Framework, I am using the Repository pattern and the Specification pattern.
My SQL Server database table has a composite primary key defined. The three columns that are part of the key are Batch_ID, RecDate, and Supplier_Date. This table as an identity column (database generated value => +1) called XREF_ID, which is not part of the PK.
My mapping class, located in Data.EF.Mapping looks like the following:
public class CrossReferenceMapping : EntityTypeConfiguration<CrossReference>
{
public CrossReferenceMapping()
{
HasKey(cpk => cpk.Batch_ID);
HasKey(cpk => cpk.RecDate);
HasKey(cpk => cpk.Supplier_Date);
Property(p => p.XREF_ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("wPRSBatchXREF");
}
}
My MemberSalesContext class (inherits from DBContext) looks like the following:
public class MemberSalesContext : DbContext, IDbContext
{
//...more DbSets here...
public DbSet<CrossReference> CrossReferences { get; set; }
//...more DbSets here...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
//...more modelBuilder here...
modelBuilder.Configurations.Add<CrossReference>(new CrossReferenceMapping());
//...more modelBuilder here...
}
}
I have a private method in a class that uses my repository to return a list of objects that get iterated over. The list I am referring to is the outermost foreach loop in the example below.
private void CloseAllReports()
{
//* get list of completed reports and close each one (populate batches)
foreach (SalesReport salesReport in GetCompletedSalesReports())
{
try
{
//* aggregate sales and revenue by each distinct supplier_date in this report
var aggregates = BatchSalesRevenue(salesReport);
//* ensure that the entire SalesReport breaks out into Batches; success or failure per SalesReport
_repository.UnitOfWork.BeginTransaction();
//* each salesReport here will result in one-to-many batches
foreach (AggregateBySupplierDate aggregate in aggregates)
{
//* get the batch range (type) from the repository
BatchType batchType = _repository.Single<BatchType>(new BatchTypeSpecification(salesReport.Batch_Type));
//* get xref from repository, *if available*
//* some will have already populated the XREF
CrossReference crossReference = _repository.Single<CrossReference>(new CrossReferenceSpecification(salesReport.Batch_ID, salesReport.RecDate, aggregate.SupplierDate));
//* create a new batch
PRSBatch batch = new PRSBatch(salesReport,
aggregate.SupplierDate,
BatchTypeCode(batchType.Description),
BatchControlNumber(batchType.Description, salesReport.RecDate, BatchTypeCode(batchType.Description)),
salesReport.Zero_Sales_Flag == false ? aggregate.SalesAmount : 1,
salesReport.Zero_Sales_Flag == false ? aggregate.RevenueAmount : 0);
//* populate CrossReference property; this will either be a crossReference object, or null
batch.CrossReference = crossReference;
//* close the batch
//* see PRSBatch partial class for business rule implementations
batch.Close();
//* check XREF to see if it needs to be added to the repository
if (crossReference == null)
{
//*add the Xref to the repository
_repository.Add<CrossReference>(batch.CrossReference);
}
//* add batch to the repository
_repository.Add<PRSBatch>(batch);
}
_repository.UnitOfWork.CommitTransaction();
}
catch (Exception ex)
{
//* log the error
_logger.Log(User, ex.Message.ToString().Trim(), ex.Source.ToString().Trim(), ex.StackTrace.ToString().Trim());
//* move on to the next completed salesReport
}
}
}
All goes well on the first iteration of the outer loop. On the second iteration of the outer loop, the code fails at _repository.UnitOfWork.CommitTransaction(). The error message returned is the following:
"The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges."
In this situation, the database changes on the second iteration were not committed successfully, but the changes in the first iteration were. I have ensured that objects in the outer and inner loops are all unique, adhering to the database primary keys.
Is there something that I am missing here? I am willing to augment my code samples, if it proves helpful. I have done everything within my capabilities to troubleshoot this issue, minus modifying the composite primary key set on the database table.
Can anyone help??? Much thanks in advance! BTW, sorry for the long post!

I am answering my own question here...
My issue had to do with how the composite primary key was being defined in my mapping class. When defining a composite primary key using EF Code First, you must define it like so:
HasKey(cpk => new { cpk.COMPANYID, cpk.RecDate, cpk.BATTYPCD, cpk.BATCTLNO });
As opposed to how I had it defined previously:
HasKey(cpk => cpk.COMPANYID);
HasKey(cpk => cpk.RecDate);
HasKey(cpk => cpk.BATTYPCD);
HasKey(cpk => cpk.BATCTLNO);
The error I was receiving was that the ObjectContext contained multiple elements of the same type that were not unique. This became an issue in my UnitOfWork on CommitTransaction. This is because when the mapping class was instanciated from my DBContext class, it executed 4 HasKey statements shown above, with only the last one for property BATCTLNO becoming the primary key (not composite). Defining them inline, as in my first code sample above, resolves the issue.
Hope this helps someone!

Related

Plugin re-using Target parameter between calls

I've created and deployed a plugin for the Update event of a custom entity but it seems when multiple users update different entities within quick succession the plugin uses the first entity it receives for each call.
To investigate further I added NLog via NuGet and at the beginning of the Execute function I generate a Guid and log the entity Id and the Guid. When I look in the log I can see the same ID and Guid logged 3-4 times before both change.
What I think is happening is the code is being run for each user but using the first entities details, applying only to the first entity.
Why is this happening and how can I stop it? The problem is users are saying the plugin is erratic.
Here is my code:
public class OnUpdateClaimSection : IPlugin
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private string logId = Guid.NewGuid().ToString();
public void Execute(IServiceProvider serviceProvider)
{
try
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
logger.Debug("{0} {1}|{2}|{3}", logId, context.MessageName, context.PrimaryEntityName, Common.GetSystemUserFullName(service, context.UserId));
var entity = context.InputParameters["Target"] as Entity;
logger.Debug("{0} {1}", logId, entity.Id);
var claimSection = GetClaimSection(service, entity.ToEntity<ClaimSection>());
CalculateClaimTotals(service, claimSection);
}
}
catch (Exception ex)
{
logger.Error("{0} Exception : {1}", logId, ex.Message);
throw;
}
}
}
Plugin classes are instantiated once by the CRM platform and are then reused for requests. Therefore you must be very careful when using class field variables, because they are not guaranteed to be thread-safe.
In your example field logId is modified in the Execute method. Race conditions of multiple threads are causing the effects you describe.
I suggest to only use plugin class fields when you have made sure that their implementation is absolutely thread-safe.

Reset id sequence or update id on Grails Test

In Grails 1.3.7, I have a code that filters objects by ID and I need to test that
The domain class has a sequence
static mapping = {
id generator: 'sequence', params[sequence: 'seq_shipping_service']
}
In the test, the object is created several times and I need the identifier to be 11 in all the tests and even though, it deletes the whole database between every test, it doesn't reset the sequence. So I would get a superior ID
foo = createFoo()
foo.id = 11l
foo.save () //This gets error
My ideas are
1) Reset somehow the id sequence so it's everytime the same number between tests
2) Set somehow the id
I don't know if I make myself clear
Personally, if I need to do something like this I:
create an object mother to spawn all required objects (i.e. foo.id == 11)
use Groovy SQL to insert data into database. In your case:
public class BlahBlahTest extends Specification {
DataSource dataSource
def setup () {
new Sql(dataSource).exec ("insert into blablah (11, ...)")
}
...
Obviously you could do anything else there - for example recreate the sequence to start with 11.

Initializing empty relationships in entities

I have entities with 1:1 or 1:M relations to other entities. All relations however are nullable.
I want to proxy some operations to the related entity. I'm giving example below. The problem is that if the relation still does not exist, I have null, so I'm ending up constantly checking for nulls, which obviously is wrong. What I would like to do is to hydrate my entities with empty objects. Reasons:
Doctrine knows what instance should be created for the field anyway. So it should just provide empty instance instead of null
I don't want to fill my code with initializations, like
$object->setSettings(new SettingsEntity)
If the requests should be proxied is somehow disputable, but I want to hide the DB representation from the client code. If my direction however is totally wrong, please point me to the right direction. I may accept that this is responsibility of the model, not of the entity, but Doctrine always returns entities to me
Sure, I can add the initialization either in the constructor of the entity, or to provide getter that creates a new instance of the object, if such does not exists. There are couple of reasons I don't want this:
I don't know how objects are actually hydrated. I assume such initialization should happen in an event and not in the constructor
I don't want to write the code for each entity (at some point, someone will forget to add the initialization in the getter) and want to make it automatically for each relation instead.
Some example code:
/**
* SomeObject
* #ORM\Entity()
* #ORM\Table(
name="some_object"
* )
*/ class SomeObject implements DataTransfer {
/**
* #ORM\OneToOne(targetEntity="Settings", mappedBy="SomeObject")
*/
protected $settings;
public function getSettings() {
return $this->settings;
}
public function get() {
$record = new \stdClass();
$record->id = $this->getId();
...
$settingsObject = $this->getSettings();
$record->someKey = $settingsObject ? $settingsObject->getSomeKey() : null;
$record->someOtherKey = $settingsObject ? $settingsObject->getSomeOtherKey() : null;
return $record;
}
Any suggestions, including hacking Doctrine, are welcome.
P.S. Doctrine-ORM version is 2.3. I can upgrade if this will help solving the problem.
I won't discuss your proxy-thingie-theory: your code, your design, I don't have enough knowlegde of these to have an opinion.
About you knowing how Doctrine hydrates its entities, you can see how it's done in \Doctrine\ORM\UnitOfWork::createEntity. It doesn't seem to invoke the constructor (uses \ReflectionClass::newInstanceWithoutConstructor, which obviously shouldn't use the constructor), but you may be interested in listening to Doctrine's post-load event (part of the lifecycle events logic).
About initializing your null properties, i.e. the code that your post-load event should trigger, you should begin by having a superclass over all of your entities: instead of class SomeObject implements DataTransfer {...}, you'd have class SomeObject extends MyEntity {...} (and have MyEntity implement DataTransfer to keep your interface). This MyEntity class would be a "mapped superclass", it would be annotated with #HasLifecycleCallbacks, and declare a method annotated with #PostLoad. There you have your hook to run your null-to-something code.
For this code to be generic (as it'd be coded from this superclass), you can rely on Doctrine's entity metadata, which retains association mappings and all data that the Unit Of Work needs to figure out its low-level DB-accessing business. It should look like the following:
/** #HasLifecycleCallbacks #MappedSuperclass ... */
public class MyEntity implements DataTransfer {
...
/** #PostLoad */
public function doPostLoad(\Doctrine\Common\Persistence\Event\LifecycleEventArgs $event) { //the argument is needed here, and is passed only since 2.4! If you don't want to upgrade, you can work around by using event listeners, but it's more complicated to implement ;)
$em = $event->getEntityManager();
$this->enableFakeMappings($em);
}
private function enableFakeMappings(\Doctrine\ORM\EntityManager $em) {
$mappings = $em->getClassMetadata(get_class($this))->getAssociationMappings(); //try and dump this $mappings array, it's full o'good things!
foreach ($mappings as $mapping) {
if (null === $this->{$mapping['fieldName']}) {
$class = $mapping['targetEntity'];
$this->{$mapping['fieldName']} = new $class(); //this could be cached in a static and cloned when needed
}
}
}
}
Now, consider the case where you have to new an entity, and want to access its properties without the null values checks: you have to forge a decent constructor for this job. As you still need the Entity Manager, the most straightforward way is to pass the EM to the constructor. In ZF2 (and Symfony I believe) you can have a service locator injected and retrieve the EM from there. Several ways, but it's another story. So, the basic, in MyEntity:
public function __construct(\Doctrine\ORM\EntityManager $em) {
$this->enableFakeMappings($em);
}
Doing this, however, would probably confuse Doctrine when the entity is persisted: what should it do with all these instantiated empty objects? It'll cascade-persist them, which is not what you want (if it is, well, you can stop reading ;)). Sacrificing cascade-persisting, an easy solution would be something like this, still in your superclass:
/** #PrePersist */
public function doPrePersist(\Doctrine\Common\Persistence\Event\LifecycleEventArgs $event) {
$em = $event->getEntityManager();
$this->disableFakeMappings($em);
}
/** #PreUpdate */
public function doPreUpdate(\Doctrine\Common\Persistence\Event\LifecycleEventArgs $event) {
$em = $event->getEntityManager();
$this->disableFakeMappings($em);
}
private function disableFakeMappings(\Doctrine\ORM\EntityManager $em) {
$uow = $em->getUnitOfWork();
$mappings = $em->getClassMetadata()->getAssociationMappings();
foreach ($mappings as $mapping) {
if (!$this->{$mapping['fieldName']} instanceof MyEntity) {
continue;
}
//"reset" faked associations: assume they're fake if the object is not yet handled by Doctrine, which breaks the cascading auto-persist... risk nothing, gain nothing, heh? ;)
if (null === $uow->getEntityState($this->{$mapping['fieldName']}, null)) {
$this->{$mapping['fieldName']} = null;
}
}
}
Hope this helps! :)

Recomputing entity changeset in onFlush listener

Consider the following schema:
[Work]
id
tags ManyToMany(targetEntity="Tag", inversedBy="works", cascade={"persist"})
[Tag]
id
works_count
works ManyToMany(targetEntity="Work", mappedBy="tags")
works_count is a counter cache for Tag::works.
I have a onFlush listener on Work that checks if Work::tags has changed, and updates each of the tags' works_count.
public function onFlush(OnFlushEventArgs $args)
{
foreach ($uow->getScheduledEntityUpdates() as $work) {
$changedTags = /* update relevant tags and return all the changed ones */
$metadata = $em->getClassMetadata('Acme\Entity\Tag');
foreach ($changedTags as $tag) {
$uow->recomputeSingleEntityChangeSet($metadata, $tag);
}
}
}
Now if I read the changesets of the updated tags, the changes of works_count appears correctly, but they don't get updated in the database..
If I replace recomputeSingleEntityChangeSet() with computeChangeSet() then everything works as expected and the DB is updated, but computeChangeSet() has an #internal Don't call from the outside. annotation on it, so I'm not sure what the consequences are..
Every source on the internet says to use recomputeSingleEntityChangeSet so why doesn't it work in this case?
P.S
The tags are managed by the EntityManager ($em->contains($tag) returns true)
This problem was related with a bug in UnitOfWork and finally it's fixed with the release of Doctrine ORM 2.4.3 on September 11, 2014. See DDC-2996 for details.
It seems that Doctrine 2.2 can merge change sets or generate new change sets, but it needs to know which. If you get it wrong, it will either replace your existing change sets or do nothing at all. I'd be very interested to know if there is a better option than this, or if this is even right.
if($uow->getEntityChangeSet($entity)) {
/** If the entity has pending changes, we need to recompute/merge. */
$uow->recomputeSingleEntityChangeSet($meta, $contact);
} else {
/** If there are no changes, we compute from scratch? */
$uow->computeChangeSet($meta, $entity);
}
In doctrine 2.4.1, use recomputeSingleEntityChangeSet only if you are changing tag in the event listener AND UOW contain tag ChangeSet (Change that happen outside of the event listener). Basically recomputeSingleEntityChangeSet is a function to merge ChangeSet for an entity.
Doc from the function
The passed entity must be a managed entity. If the entity already has a change set because this method is invoked during a commit cycle then the change sets are added whereby changes detected in this method prevail.
NOTE: You need to make sure UOW already have ChangeSet for the entity, otherwise it will not merge.
For future readers, at all cost try to avoid the listeners. Those are hardly testable, your domain should not rely on magic. Consider OP's test case how to achieve the same without Doctrine events:
Work class:
public function addTag(Tag $tag): void
{
if (!$this->tags->contains($tag)) {
$this->tags->add($tag);
$tag->addWork($this);
}
}
Tag class:
public function addWork(Work $work): void
{
if (!$this->works->contains($work)) {
$work->addTag($this);
$this->works->add($work);
$this->worksCount = count($this->works);
}
}
TagTest class:
public function testItUpdatesWorksCountWhenWorkIsAdded()
{
$tag = new Tag();
$tag->addWork(new Work());
$tag->addWork(new Work());
$this->assertSame(2, $tag->getWorkCount());
}
public function testItDoesNotUpdateWorksCountIfWorkIsAlreadyInCollection()
{
$tag = new Tag();
$work = new Work();
$tag->addWork($work);
$tag->addWork($work);
$this->assertSame(1, $tag->getWorkCount());
}

What's the lazy strategy and how does it work?

I have a problem. I'm learning JPA. I'm using embedded OpenEJB container in unit tests, but only working is #OneToMany(fetch=EAGER). Otherwise is the collection allways null. I haven't found, how the lazy strategy works, how the container fills the data and in which circumstances triggers the container the loading action?
I have read, that the action triggers when the getter is being called. But when I have the code:
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities = new Set<AnotherEntities>();
...
public Set<AnotherEntities> getEntities() {
return entities;
}
I'm always getting null. I thing, the LAZY strategy cannot be tested with embedded container. The problem might be also in the bidirectional relation.
Does have anybody else similar expiriences with the JPA testing?
Attachments
The real test case with setup:
#RunWith(UnitilsJUnit4TestClassRunner.class)
#DataSet("dataSource.xml")
public class UnitilsCheck extends UnitilsJUnit4 {
private Persister prs;
public UnitilsCheck() {
Throwable err = null;
try {
Class.forName("org.hsqldb.jdbcDriver").newInstance();
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
props.put("ds", "new://Resource?type=DataSource");
props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver");
props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB");
props.put("ds.UserName", "sa");
props.put("ds.Password", "");
props.put("ds.JtaManaged", "true");
Context context = new InitialContext(props);
prs = (Persister) context.lookup("PersisterImplRemote");
}
catch (Throwable e) {
e.printStackTrace();
err = e;
}
TestCase.assertNull(err);
}
#Test
public void obtainNickNamesLazily() {
TestCase.assertNotNull(prs);
PersistableObject po = prs.findByPrimaryKey("Ferenc");
TestCase.assertNotNull(po);
Collection<NickNames> nicks = po.getNickNames();
TestCase.assertNotNull(nicks);
TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString());
}
}
The bean Presister is the bean mediating access to the entity beans. The crucial code of class follows:
#PersistenceUnit(unitName="PhonePU")
protected EntityManagerFactory emf;
public PhoneBook findByPrimaryKey(String name) {
EntityManager em = emf.createEntityManager();
PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name);
em.close();
return phonebook;
}
Entity PhoneBook is one line of phone book (also person). One person can have zero or more nick names. With EAGER strategy it works. With LAZY the collection is allways null. May be the problem is in the detaching of objects. (See OpenEJB - JPA Concepts, part Caches and detaching.) But in the manual is written, that the collection can be sometimes (more like manytimes) empty, but not null.
The problem is in the life cycle of an entity. (Geronimo uses OpenJPA, so le't see OpenJPA tutorial, part Entity Lifecycle Management.) The application uses container managed transactions. Each method call on the bean Persiser runs in an own transation. And the persistency context depends on the transaction. The entity is disconnected from its context at the end of the transaction, thus at the end of the method. I tried to get the entity and on second line in the same method to get the collection of nick names and it worked. So the problem was identifyed: I cannot get additionally any entity data from the data store without re-attaching the entity to some persistency context. The entity is re-attached by the EntityManager.merge() method.
The code needs more correctures. Because the entity cannot obtain the EntityManager reference and re-attach itself, the method returning nick names must be moved to the Persister class. (The comment Heureka marks the critical line re-attaching the entity.)
public Collection<NickNames> getNickNamesFor(PhoneBook pb) {
//emf is an EntityManagerFactory reference
EntityManager em = emf.createEntityManager();
PhoneBook pb = em.merge(pb); //Heureka!
Collection<NickNames> nicks = pb.getNickNames();
em.close();
return nicks;
}
The collection is then obtained in this way:
//I have a PhoneBook instance pb
//pb.getNickNames() returns null only
//I have a Persister instance pe
nicks = pe.getNickNames(pb);
That's all.
You can have a look at my second question concerning this topic I'have asked on this forum. It is the qustion OpenJPA - lazy fetching does not work.
How I would write the code
#Entity
public class MyEntity {
#OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities;
// Constructor for JPA
// Fields aren't initalized here so that each em.load
// won't create unnecessary objects
private MyEntity() {}
// Factory method for the rest
// Have field initialization with default values here
public static MyEntity create() {
MyEntity e = new MyEntity();
e.entities = new Set<AnotherEntities>();
return e;
}
public Set<AnotherEntities> getEntities() {
return entities;
}
}
Idea no 2:
I just thought that the order of operations in EAGER and LAZY fetching may differ i.e. EAGER fetching may
Declare field entities
Fetch value for entities (I'd assume null)
Set value of entities to new Set<T>()
while LAZY may
Declare field `entities
set value of entities to new Set<T>()
Fetch value for entities (I'd assume null)'
Have to find a citation for this as well.
Idea no 1: (Not the right answer)
What if you'd annotate the getter instead of the field? This should instruct JPA to use getters and setters instead of field access.
In the Java Persistence API, an entity can have field-based or
property-based access. In field-based access, the persistence provider
accesses the state of the entity directly through its instance
variables. In property-based access, the persistence provider uses
JavaBeans-style get/set accessor methods to access the entity's
persistent properties.
From The Java Persistence API - A Simpler Programming Model for Entity Persistence