EclipseLink cache usage with CheckCacheThenDatabase - jpa

My scenario is similar to the following:
User a = ...; //has email pippo#gmail.com
em.remove(a);
...
User aUser = findUserByEmail("pippo#gmail.com");
where findUser queries the object using a named query marked as CheckCacheThenDatabase. Unfortunately, it returns the object (in removed status) and not null as expected.
So, why the L2 cache is not updated accordingly?

Related

Slick insert not working while trying to return inserted row

My goal here is to retrieve the Board entity upon insert. If the entity exists then I just want to return the existing object (which coincides with the argument of the add method). Otherwise I'd like to return the new row inserted in the database.
I am using Play 2.7 with Slick 3.2 and MySQL 5.7.
The implementation is based on this answer which is more than insightful.
Also from Essential Slick
exec(messages returning messages +=
Message("Dave", "So... what do we do now?"))
DAO code
#Singleton
class SlickDao #Inject()(db: Database,implicit val playDefaultContext: ExecutionContext) extends MyDao {
override def add(board: Board): Future[Board] = {
val insert = Boards
.filter(b => b.id === board.id && ).exists.result.flatMap { exists =>
if (!exists) Boards returning Boards += board
else DBIO.successful(board) // no-op - return specified board
}.transactionally
db.run(insert)
}
EDIT: also tried replacing the += part with
Boards returning Boards.map(_.id) into { (b, boardId) => sb.copy(id = boardId) } += board
and this does not work either
The table definition is the following:
object Board {
val Boards: TableQuery[BoardTable] = TableQuery[BoardTable]
class BoardTable(tag: Tag) extends Table[BoardRow](tag, "BOARDS") {
// columns
def id = column[String]("ID", O.Length(128))
def x = column[String]("X")
def y = column[Option[Int]]("Y")
// foreign key definitions
.....
// primary key definitions
def pk = primaryKey("PK_BOARDS", (id,y))
// default projection
def * = (boardId, x, y).mapTo[BoardRow]
}
}
I would expect that there would e a new row in the table but although the exists query gets executed
select exists(select `ID`, `X`, `Y`
from `BOARDS`
where ((`ID` = '92f10c23-2087-409a-9c4f-eb2d4d6c841f'));
and the result is false there is no insert.
There is neither any logging in the database that any insert statements are received (I am referring to the general_log file)
So first of all the problem for the query execution was a mishandling of the futures that the DAO produced. I was assigning the insert statement to a future but this future was never submitted to an execution context. My bad even more so that I did not mention it in the description of the problem.
But when this was actually fixed I could see the actual error in the logs of my application. The stack trace was the following:
slick.SlickException: This DBMS allows only a single column to be returned from an INSERT, and that column must be an AutoInc column.
at slick.jdbc.JdbcStatementBuilderComponent$JdbcCompiledInsert.buildReturnColumns(JdbcStatementBuilderComponent.scala:67)
at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.x$17$lzycompute(JdbcActionComponent.scala:659)
at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.x$17(JdbcActionComponent.scala:659)
at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.keyColumns$lzycompute(JdbcActionComponent.scala:659)
at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.keyColumns(JdbcActionComponent.scala:659)
So this is a MySQL thing in its core. I had to redesign my schema in order to make this retrieval after insert possible. This redesign includes an introduction of a dedicated primary key (completely unrelated to the business logic) which is also an AutoInc column as the stack trace prescribes.
In the end the solution becomes too involved and instead decided to use the actual argument of the add method to return if the insert was actually successful. So the implementation of the add method ended up being something like this
override def add(board: Board): Future[Board] = {
db.run(Boards.insertOrUpdate(board).map(_ => board))
}
while there was some appropriate Future error handling in the controller which was invoking the underlying repo.
If you're lucky enough and not using MySQL with Slick I suppose you might have been able to do this without a dedicated AutoInc primary key. If not then I suppose this is a one way road.

GORM low level api finds object (Mongodb record) but its still NULL?

I have code like this in a controller method:
DB db = mongoClient.getDB("twcdb");
DBCollection coll = db.getCollection('countrycodes')
println coll.findOne()
println coll.findOne().class
and I get this output at the console:
[_id:539848b2119918654e7e90c3, Country:Bermuda, Alpha2:BM, Aplha3:BMU, Numeric:60, FIPS:BD, IGA:Model 2]
null
So how can it be that it finds a record but its class is null? Is this because this record isn't modeled by any of my domain classes? It does recognize the record's individual fields as Strings which I just tested but the record overall is classed NULL? How, why?
you should never call class on an object as there are scenarios where this could fail (e.g. getProperty('class') gets called or you are on a "mapish" object, which means that groovy will call get('class') for you -- which is the case for the BasicDBObject (subsubclass of a LinkedHashMap)). always use getClass()

NullReferenceException while trying to including a one-to-many relationship item after saving parent

Framework: I'm using using MVC 3 + EntityFramework 4.1 Code-First.
Concept: One Legislation entity has many Provision entities. The idea is that the user enters a Legislation entity, that gets saved then the function that saves it passes it along to another function to see whether that Legislation has a ShortTitle. If it does, then it formats it into a properly worded string and includes it as the Legislation's first Provision, then saves the changes to db.
Issue: The problem is, I've tried coding it in different ways, I keep getting a NullReferenceException, telling me to create a new object instance with the "new" keyword, and points me to the savedLegislation.Provisions.Add(provision); line in my second function.
Here are the two functions at issue, this first one saves the Legislation proper:
public Legislation Save(NewLegislationView legislation)
{
Legislation newLegislation = new Legislation();
// Simple transfers
newLegislation.ShortTile = legislation.ShortTile;
newLegislation.LongTitle = legislation.LongTitle;
newLegislation.BillType = legislation.BillType;
newLegislation.OriginatingChamber = legislation.OriginatingChamber;
newLegislation.Preamble = legislation.Preamble;
// More complicated properties
newLegislation.Stage = 1;
this.NumberBill(newLegislation); // Provides bill number
newLegislation.Parliament = db.LegislativeSessions.First(p => p.Ending >= DateTime.Today);
newLegislation.Sponsor = db.Members.Single(m => m.Username == HttpContext.Current.User.Identity.Name);
// And save
db.Legislations.Add(newLegislation);
db.SaveChanges();
// Check for Short titles
this.IncludeShortTitle(newLegislation);
// return the saved legislation
return newLegislation;
}
And the second function which is invoked by the first one deals with checking whether ShortTitle is not empty and create a Provision that is related to that Legislation, then save changes.
public void IncludeShortTitle(Legislation legislation)
{
var savedLegislation = db.Legislations.Find(legislation.LegislationID);
if (savedLegislation.ShortTile.Any() && savedLegislation.ShortTile.ToString().Length >= 5)
{
string shortTitle = "This Act may be cited as the <i>" + savedLegislation.ShortTile.ToString() + "</i>.";
var provision = new Provision()
{
Article = Numbers.CountOrNull(savedLegislation.Provisions) + 1,
Proponent = savedLegislation.Sponsor,
Text = shortTitle
};
savedLegislation.Provisions.Add(provision);
db.SaveChanges();
}
}
I've been researching how SaveChanges() works and whether it is properly returning the updated entity, it does (since I get no issue looking it up in the second function). If it works properly, and the legislation is found and the provision is newly created in the second function, I don't see what is the "null" reference it keeps spitting out.
The null reference in this case would be savedLegislation.Provisions. The Provisions collection won't be initialized to a new List<Provision> when EF returns your Legislation instance from the db.Legislations.Find(...) method.
The first thing I'd try is something like this:
var savedLegislation = db.Legislations
.Include("Provisions")
.First(l => l.LegislationID == legislation.LegislationID);
... but I'd also consider just using the legislation instance that was passed into the method rather than fetching it from the database again.

Delete child objects

I am trying to update a resource as follows:
public void Update(Resource resource) {
Resource _resource = _resourceRepository.First(r => r.Id == resource.Id);
_resource.Content = resource.Content;
_resource.Description = resource.Description;
_resource.Locked = resource.Locked;
_resource.Name = resource.Name;
_resource.Restrictions.ToList().ForEach(r => _resource.Restrictions.Remove(r));
foreach (Restriction restriction in resource.Restrictions)
_resource.Restrictions.Add(new Restriction { Property = _propertyRepository.First(p => p.Id == restriction.Property.Id), Value = restriction.Value });
} // Update
I have something similar, and working, to create a resource with only one difference: I do not remove the Restrictions.
I am getting the following error:
A relationship from the
'Restrictions_ResourceId_FK'
AssociationSet is in the 'Deleted'
state. Given multiplicity constraints,
a corresponding 'Restrictions' must
also in the 'Deleted' state.
What am I missing?
EF did exactly what you told him to do. Removing item from parent object navigation collection only removes relation between parent and child object. It means it only sets ResourceId in Restriction to null which is not allowed by your entity model.
If your Restriction can't exist without related resource you should model relation as Identifying. It means that Restriction primary key will also contain ResourceId column. When you then remove restriction from parent object collection, EF will delete restriction instead of setting ResourceId to null.
I was having similar problems since the opposite of Add() obviously seemed Remove().
You must use the DeleteObject() function instead to delete child items.
Thanks.

ADO.NET Mapping From SQLDataReader to Domain Object?

I have a very simple mapping function called "BuildEntity" that does the usual boring "left/right" coding required to dump my reader data into my domain object. (shown below) My question is this - If I don't bring back every column in this mapping as is, I get the "System.IndexOutOfRangeException" exception and wanted to know if ado.net had anything to correct this so I don't need to bring back every column with each call into SQL ...
What I'm really looking for is something like "IsValidColumn" so I can keep this 1 mapping function throughout my DataAccess class with all the left/right mappings defined - and have it work even when a sproc doesn't return every column listed ...
Using reader As SqlDataReader = cmd.ExecuteReader()
Dim product As Product
While reader.Read()
product = New Product()
product.ID = Convert.ToInt32(reader("ProductID"))
product.SupplierID = Convert.ToInt32(reader("SupplierID"))
product.CategoryID = Convert.ToInt32(reader("CategoryID"))
product.ProductName = Convert.ToString(reader("ProductName"))
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
productList.Add(product)
End While
Also check out this extension method I wrote for use on data commands:
public static void Fill<T>(this IDbCommand cmd,
IList<T> list, Func<IDataReader, T> rowConverter)
{
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
list.Add(rowConverter(rdr));
}
}
}
You can use it like this:
cmd.Fill(products, r => r.GetProduct());
Where "products" is the IList<Product> you want to populate, and "GetProduct" contains the logic to create a Product instance from a data reader. It won't help with this specific problem of not having all the fields present, but if you're doing a lot of old-fashioned ADO.NET like this it can be quite handy.
Although connection.GetSchema("Tables") does return meta data about the tables in your database, it won't return everything in your sproc if you define any custom columns.
For example, if you throw in some random ad-hoc column like *SELECT ProductName,'Testing' As ProductTestName FROM dbo.Products" you won't see 'ProductTestName' as a column because it's not in the Schema of the Products table. To solve this, and ask for every column available in the returned data, leverage a method on the SqlDataReader object "GetSchemaTable()"
If I add this to the existing code sample you listed in your original question, you will notice just after the reader is declared I add a data table to capture the meta data from the reader itself. Next I loop through this meta data and add each column to another table that I use in the left-right code to check if each column exists.
Updated Source Code
Using reader As SqlDataReader = cmd.ExecuteReader()
Dim table As DataTable = reader.GetSchemaTable()
Dim colNames As New DataTable()
For Each row As DataRow In table.Rows
colNames.Columns.Add(row.ItemArray(0))
Next
Dim product As Product While reader.Read()
product = New Product()
If Not colNames.Columns("ProductID") Is Nothing Then
product.ID = Convert.ToInt32(reader("ProductID"))
End If
product.SupplierID = Convert.ToInt32(reader("SupplierID"))
product.CategoryID = Convert.ToInt32(reader("CategoryID"))
product.ProductName = Convert.ToString(reader("ProductName"))
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
productList.Add(product)
End While
This is a hack to be honest, as you should return every column to hydrate your object correctly. But I thought to include this reader method as it would actually grab all the columns, even if they are not defined in your table schema.
This approach to mapping your relational data into your domain model might cause some issues when you get into a lazy loading scenario.
Why not just have each sproc return complete column set, using null, -1, or acceptable values where you don't have the data. Avoids having to catch IndexOutOfRangeException or re-writing everything in LinqToSql.
Use the GetSchemaTable() method to retrieve the metadata of the DataReader. The DataTable that is returned can be used to check if a specific column is present or not.
Why don't you use LinqToSql - everything you need is done automatically. For the sake of being general you can use any other ORM tool for .NET
If you don't want to use an ORM you can also use reflection for things like this (though in this case because ProductID is not named the same on both sides, you couldn't do it in the simplistic fashion demonstrated here):
List Provider in C#
I would call reader.GetOrdinal for each field name before starting the while loop. Unfortunately GetOrdinal throws an IndexOutOfRangeException if the field doesn't exist, so it won't be very performant.
You could probably store the results in a Dictionary<string, int> and use its ContainsKey method to determine if the field was supplied.
I ended up writing my own, but this mapper is pretty good (and simple): https://code.google.com/p/dapper-dot-net/