OrientDB - Linking Records in a Transaction Does not Work - orientdb

Scenario
I have two classes. Schema given below;
CLASS B {
PROPERTY name STRING
}
CLASS A {
PROPERTY name STRING
PROPERTY bLinkList LINKLIST B
}
I want to insert a record to Class B, insert a record to Class A and link new record of Class B to the new record of Class A. I want to do this in a transaction.
Code
I'm using a server side function for doing this. Following is the code.
db.begin();
var bRid = db.command("INSERT INTO B (name) VALUES(\"Jack\") RETURN #rid");
db.command("INSERT INTO A (name) VALUES(\"Jack\")");
db.command("UPDATE A ADD bLinkList = " + bRid);
db.commit();
Facts
I'm using OrientDB Version : 2.0.3. My DB is a Document DB
Observation
With in a transaction, this does not work. For bLinkList in Class A, null is inserted
With out the transaction this works.
I've checked the rid returned after insertion with in the transaction and as expected they are temporary rids. As per documentation and few forum posts I've referred, the records are sent to the server and the transaction is re-created in the server side before the commit, hence the consistency of the temporary rids created with in the transaction at client side are maintained.
Unfortunately this does not work. Some help to figure out what's going in here would be highly appreciated.
Cheers!
Omega

Related

Entity Framework - Last ID of Entree

Currently I am programming an application which saves and deletes entries in a database (code first with entity framework). My question is how can I get the next database id (configured with auto increment - so it added automatically +1).
I tried something like:
var a = databaseContext.MyObject.LastOrDefault().Id;
var myNextDatabaseId = a+1;
This pseudo code is working for most of the cases. But if i had 5 entrees in my database and delete all the five entree's my next database-counter would be 6. When i'm using the code above it will return "null" becouse there is really no entree. But i must get the next database auto increment id.
Is there a possibility which doesn't create a new database entry? Think this shouldn't be necessary.
For example following data construct:
Inserted entry one (internal id = 1)
Inserted entry two (internal id = 2)
Delete entry one
Delete entry two
Read last database entry (entry = null). All data was deleted but I am trying to receive the next auto-increment id 3
Use an explicit transaction scope and identity column. Trying to maintain IDs at the application level isn't scale-able and will be prone to concurrency errors.
Ideally the transaction should span the web service call to roll back automatically if the call fails. With an explicit transaction you can call your context.SaveChanges() which will expose the next ID assigned to the entity, and then roll back if the web service call fails. This can be a transaction managed by the context or TransactionScope.
see: https://msdn.microsoft.com/en-us/library/dn456843(v=vs.113).aspx

Retrieving some columns from database with Breeze.js, and still be able to update database

I am new to Breeze.js, but really enjoy it so far. I ran into an issue with updating a database with Breeze.js, when selecting only portion of columns of a model.
When I ran this statement:
$scope.emFac.entityQuery.from('Company');
the company entity matches my EF entity, retrieves all columns, creates entityAspect, and all is working fine when updating database:
However, when I retrieve only portion of corresponding Model's columns, Breeze.js returns anonymous object with specified properties (retrieving data works, but not updating does not), without the entityAspect, which is being used for tracking changes.
Here is the code with select statement:
$scope.emFac.entityQuery.from('Company').select('companyId, displayName');
Is there a way to retrieve only some columns of EF Model columns, and still track changes with Breeze.js, needed for database updates?
As you've discovered, Breeze treats the incoming data as plain objects instead of entities when you use select.
Your choices are:
On the server, Create a CustomerLite or similar object, and have a server endpoint that returns those without the need for select; OR
On the client, get the results from the query and create entities from each object, with status Unchanged
Example of #2:
var entities = [];
em.executeQuery(customerProjectionQuery).then(queryResult => {
queryResult.results.forEach(obj => {
// obj contains values to initialize entity
var entity = em.createEntity(Customer.prototype.entityType, obj, EntityState.Unchanged);
entities.push(entity);
});
})
Either way, you will need to ensure that your saveChanges endpoint on the server can handle saving the truncated Customer objects without wiping out the other fields.

entity framework update foreign key throws exception if AutoDetectChangesEnabled set false

I have table A and B
A like : id
name
bid
B like : id
type
in table A has a data record reference with B1,now I want update A reference with B2.
in my unitofwork if I set AutoDetectChangesEnabled = true it's work ok, but I set AutoDetectChangesEnabled = false reason is I want to up speed throw the exception like this:
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: A referential integrity constraint violation occurred: The property value(s) of 'GoodsKind.goods_kind_id' on one end of a relationship do not match the property value(s) of 'EnrolmentType.goods_kind' on the other end."
how cand i do?
I just had this error as well. The problem for me was that I have a complex type. When I changed the master record (let's say Person) I also wanted to change the complex type List with his contact information(s). So when I tried to save them both in one screen I got this error. Check if you fill all the ids on your screen for the master record and the complex type records. Check if they are posted to the server (if you use in example MVC). You can do this by checking the Bind statement by your MVC action.
The error says that the ID and the object specified doesn't match. This means that you are saying that A has a B with ID=2 but at the same time you have A with an object of type B with ID=5. Because you are working in a disconnected environment, EF doesn't know which one is the correct. To solve this issue you can do one of the following things:
-Get the object from EF, modify it and then save (connected environment).
OR
-Update the IDs manually (update A setting ID=5 because the object B has ID=5).
Always remember that EF tracks changes if it is in a connected environment and the tracking is enabled. If not, it has no clue of the changes you made until it tries to save it in the DB (where the object is compared with the values in the DB). One thing that you can do to manually tell EF that the entity has been modified in a disconnected environment is:
dbContext.Entry(objectA).State = EntityState.Modified;

Entity Framework : map duplicate tables to single entity at runtime?

I have a legacy database with a particular table -- I will call it ItemTable -- that can have billions of rows of data. To overcome database restrictions, we have decided to split the table into "silos" whenever the number of rows reaches 100,000,000. So, ItemTable will exist, then a procedure will run in the middle of the night to check the number of rows. If numberOfRows is > 100,000,000 then silo1_ItemTable will be created. Any Items added to the database from now on will be added to silo1_ItemTable (until it grows to big, then silo2_ItemTable will exist...)
ItemTable and silo1_ItemTable can be mapped to the same Item entity because the table structures are identical, but I am not sure how to set this mapping up at runtime, or how to specify the table name for my queries. All inserts should be added to the latest siloX_ItemTable, and all Reads should be from a specified siloX_ItemTable.
I have a separate siloTracker table that will give me the table name to insert/read the data from, but I am not sure how I can use this with entity framework...
Thoughts?
You could try to use the Entity Inheritance to get this. So you have a base class which has all the fields mapped to ItemTable and then you have descendant classes that inherit from ItemTable entity and is mapped to the silo tables in the db. Every time you create a new silo you create a new entity mapped to that silo table.
[Table("ItemTable")]
public class Item
{
//All the fields in the table goes here
}
[Table("silo1_ItemTable")]
public class Silo1Item : Item
{
}
[Table("silo2_ItemTable")]
public class Silo2Item : Item
{
}
You can find more information on this here
Other option is to create a view that creates a union of all those table and map your entity to that view.
As mentioned in my comment, to solve this problem I am using the SQLQuery method that is exposed by DBSet. Since all my item tables have the exact same schema, I can use the SQLQuery to define my own query and I can pass in the name of the table to the query. Tested on my system and it is working well.
See this link for an explanation of running raw queries with entity framework:
EF raw query documentation
If anyone has a better way to solve my question, please leave a comment.
[UPDATE]
I agree that stored procedures are also a great option, but for some reason my management is very resistant to make any changes to our database. It is easier for me (and our customers) to put the sql in code and acknowledge the fact that there is raw sql. At least I can hide it from the other layers rather easily.
[/UPDATE]
Possible solution for this problem may be using context initialization with DbCompiledModel param:
var builder = new DbModelBuilder(DbModelBuilderVersion.V6_0);
builder.Configurations.Add(new EntityTypeConfiguration<EntityName>());
builder.Entity<EntityName>().ToTable("TableNameDefinedInRuntime");
var dynamicContext = new MyDbContext(builder.Build(context.Database.Connection).Compile());
For some reason in EF6 it fails on second table request, but mapping inside context looks correct on the moment of execution.

JPA Join Not Cascading for jUnit Test

I have a many-to-many relationship between 2 tables that I define with a join table.
//MyClassA
#ManyToMany
#JoinTable(name="A_TO_B",
joinColumns=#JoinColumn(name="A_UUID"),
inverseJoinColumns=#JoinColumn(name="B_UUID")
)
private List<MyClassB> classBs = new ArrayList<MyClassB>();
//MyClassB
#ManyToMany(mappedBy="classBs")
private List<MyClassA> classAs = new ArrayList<MyClassA>();
Due to company architecture restrictions, the join table must have a UUID column.
I have a DAO method called associateItems which should insert a row into the join column. In order to test everything, I do the following in a jUnit test.
myDao.associateItems(classAItem, classBItem);
classAItem = myDao.get(classAItem.getUuid());
classBItem = myDao.get(classBItem.getUuid());
assertEquals(1, classAItem.getClassBs().size());
assertEquals(1, classBItem.getClassAs().size());
This test fails on the last 2 lines.
In my DAO, I have tried a number of things. I tried adding the classAItem and classBItem to each others lists and merging them. But this causes an error because the join table object doesn't have a UUID. And I tried creating the join table object and persisting that. But then the last 2 lines of the test fail because it thinks the size of the lists are 0.
I have been sticking with the second solution (fail is better than error).
public void associateItems(MyClassA classAItem, MyClassB classBItem) {
//UUID populated in constructor
AToB association = new AToB(classAItem, classBItem);
entityManager.persist(association);
}
I know that the join table item is getting inserted into the database. I also manually entered a join table item and made sure the lists are populated when an association is found. So the test just has an issue with making the join table item and then associating the relevant lists.
I have tried messing with cascades, fetch types, and flushes. But I can't seem to find a way to make the tests pass.
Anyone know what I need to do to fix this?
This was actually a problem with the get method in the DAO. I added the following hint and test run without failure.
query.setHint(QueryHints.REFRESH, HintValues.TRUE);