I have a basic OneToMany relationship between an Administratorand Role.
The owning side is Administrator:
/**
* #ORM\OneToMany(targetEntity="App\PublicBundle\Entity\Role", mappedBy="administrator", cascade="persist")
**/
private $roles;
public function __construct() {
$this->roles = new ArrayCollection();
}
The inverse side is Role.
/**
* #ORM\ManyToOne(targetEntity="App\PublicBundle\Entity\Administrator", inversedBy="roles")
* #ORM\JoinColumn(name="admin_id", referencedColumnName="admin_id")
**/
private $administrator;
The Administrator can have many Roles like ROLE_ADMIN or ROLE_USER.
The code to save them atomically is...
$administrator = new Administrator();
$administrator->setName('Mario');
$administrator->setLastname('Superman');
$administrator->setUsername('mario#gmail.com');
$administrator->setPassword('password');
$role_admin = new Role();
$role_admin->setRole('ROLE_ADMIN');
$role_admin->setAdministrator($administrator);
$role_user = new Role();
$role_user->setRole('ROLE_USER');
$role_user->setAdministrator($administrator);
$administrator->setRoles($role_admin);
$administrator->setRoles($role_user);
$em->persist($administrator);
$em->persist($role_user);
$em->persist($role_admin);
$em->flush();
Basic stuff. This code is inside a Symfony2 controller that is called via Ajax. It throws an Integrity constraint violation where he says that he cannot put null in admin_id column beacuse it is null. It also emmits two notices that say undefined index role_id.
The strange stuff is that the rows are not saved but the admin_id on the administrators table gets incremented.
The even stranger stuff is that I have a UnitTest that does the same thing (literally the same thing with the same code) and persists the entities.
So how code test code work but the same code in the live controller doesn't?
EDIT: I call the controller via Ajax and it doesn't get persisted but if I go straight to the url that make a request with ajax, it gets persisted two times. Ones for the ajax post request and the second when i go straight to link on the browser. Am I missing something basic here beacuse I have a feeling that I am.
The answer is that my database was named as test_suite what mysql regarded as a test database. I don't know the details but it seems that every database that has test_ like names is regared by mysql in special rules. As I said, i don't know the details but I couldn't make a transactional insert statement in that kind of database.
When I created a new database called suit, everything worked.
This blog post
doesn't say that transactional insert statements are prohibited in test databases, but it seems that it is a bad idea to name your database test_ like. I didn't know that and had to learn it the hard way
Related
Using the amazing LinqPad. Is there a way to clear all pending database changes to the built-in LinqToSql DataContext (the UserQuery object which is this)?
Example LinqPad file, connection to a basic mssql database with tb_person table.
void Main()
{
var newRow = new tb_person() {FirstName = "Bob"};
// do lots of db updates, deletes, inserts....
tb_persons.InsertOnSubmit(newRow);
// how to do this, revert all pending Db changes?
//this.SomeMethodToDiscardChanges()
}
I found 2 option, neither seems to be ideal, maybe there is a LinqPad specific way outside of LinqToSql?
Create a new DataContext, how to do this in LinqPad?
DataContext.Refresh() method passing in every added or changed entity, cumbersome!
References
How to clear the DataContext cache on Linq to Sql
No guarantees, but you can try
this.Uncapsulate().ClearCache();
I've used this and it seems to work, but I've never used it on a production database.
Alternatively, you can create a new DataContext using
var dc = new TypedDataContext(this.Connection.ConnectionString);
but of course you can't assign to this which means that you need to be careful to prefix all your queries and references to use dc.
Let's say i have two Doctrine entities:
Users and Messages
Every user can have 'n' messages.
Now I want to display the mailbox for a user so I fetch the user entity from the ORM and from this entity I get all messages. No problem so far.
But now i want to have some more complexe filtering of the messages. For example: Max age, Max count, blacklisting some words etc. So the default getter method of the entity for getting the messages isn't enough.
How can i solve this?
A entity repository is the first thing i found but then i have to ask this repoitory from outside of the user object which breaks the relationship of user and message (repository->getMessagesForUser(userId,...) instead of user->getMessages(...)) which doesn't look like a 'clean' OOP solution for me.
Another way i could think of is to ignore all this fancy ORM stuff and write my own models and getting the informations from the database on the lowest ORM or even DBAL layer. And ether wrap the entity or fill the fields of my own models manually. But then i ask myself: "Why did i use Doctrine?".
So what's the best practice for this case. By the way i use Symfony 2.
In this specific case, I would definitely make the Message its own aggregate, and therefore would create a Repository for it, and remove the relationship from User to Message. The User can have many Messages anyway, so it would be very inefficient to use the other approach.
I would then create specific methods in the MessageRepository:
class MessageRepository
{
public function findByUser(User $user) {
// ...
}
public function findReadMessagesByUser(User $user) {
// ...
}
}
I am new to LINQ to SQL, but have done a lot of database development in the past.
The software I just started working on uses:
// MyDataContext is a sub class of DataContext, that is generated with SqlMetal
MyDataContext db = new MyDataContext (connectionString);
db.CreateDatabase();
to create the database when it is first run.
I need to add some indexes to the tables....
How can I tell the DataContext what indexes I want?
Otherwise how do I control this?
(I could use a sql script, but I like the ideal that db.CreateDatabase will always create a database that matches the data access code)
(For better, or worse the software has full access to the database server and our software often create databases on the fly to store result of model runs etc, so please don’t tell me we should not be creating databases from code)
I seem not to be the only person hitting limts on DataContext.CreateDatabase() see also http://csainty.blogspot.com/2008/02/linq-to-sql-be-careful-of.html
As far as I know the DataContext.CreateDatabase method can only create primary keys.
When you look at the DBML directly, you will see that there are no elements for defining an index. Therefore it is, IMHO, save to assume that CreateDatabase cannot do it.
So the only way I can think of for creating indexes "automatically" is by first calling DataContext.CreateDatabase and then calling DataContext.ExecuteCommand to add the indexes to the tables that were just created.
You can execute SQL Command on DatabaseCreated method.
public partial class DatabaseModelsDataContext : System.Data.Linq.DataContext
{
partial void OnCreated ()
{
var cmdText = #"
IF EXISTS (SELECT name FROM sys.indexes WHERE name = N'IX_LeafKey')
DROP INDEX IX_MyTableColumn
ON [mydb].[dbo].[Leaf];
CREATE INDEX IX_MyTableColumn
ON [mydb].[dbo].[MyTable] ([column]) ;";
ExecuteCommand(cmdText);
}
}
I have a standard update happening via linq to sql but the data does not persist to the database.
I am using an auto-generated class via the .dbml file designer.
The update statement is below:
public static void UpdateEmailsInWorkingTable(Guid emailGuid, string modifiedEmail)
{
using (EmailDBDataContext DBContext = new EmailDBDataContext())
{
EmailAddress_Update EAUpdated = (from e in DBContext.EmailAddress_Updates
where e.EmailGuid == emailGuid
select e).SingleOrDefault();
EAUpdated.EmailAddress = modifiedEmail;
EAUpdated.IsValid = 'Y';
EAUpdated.UpdateFlag = true;
EAUpdated.LastChangedDtTm = DateTime.Now;
try
{
DBContext.SubmitChanges(ConflictMode.FailOnFirstConflict);
}
catch (ChangeConflictException ex)
{
// do stuff here
}
}
}
I looked through my auto-generated DataContext class and the only glaring difference is that the table in question EmailAddress_Update does not implement the two interfaces INotifyPropertyChanging and INotifyPropertyChanged that the other auto-generated entities do.
I am assuming that this is the cause of why the changes are not being persisted is it not???
To put it simply none of the Extensibility Method Definitions get generated for any part of this one class. If this is the cause of my problems, what in the database would be causing this to not auto-generate properly??
Thanks~
I posted this question on MSDN as well here: MSDN Linq to Sql if you wanted to see the replies. But I found part of the reason why the code doesn't generate.
Here is a piece from my MSDN response:
I created a small test table without a primary key and added it to the designer and sure enough it didn't generate any of the Extensibility methods for that instance.
So I then added a primary key to the same table and re-added it to the designer and sure enough all of the extensibility methods and change tracking events were generated.
My question now is why must there be a primary key for this stuff to auto-generate?
Ok so to answer my own question "My question now is why must there be a primary key for this stuff to auto-generate?" I found it in the book Pro LINQ written by Joe Joseph C. Rattz, Jr.
I was reading how to handle views versus tables and he says this:
"Because the entity classes generated for views do not contain entity class properties that are mapped as primary keys, they are read-only. If you consider that without primary keys, the DataContext has no effective way to provide identity tracking, this makes sense."
Mystery and problem solved.
I ran into an interesting problem while using DLINQ. When I instantiate an entity, calling .SubmitChanges() on the DataContext will insert a new row into the database - without having ever called .Insert[All]OnSubmit(...).
//Code sample:
Data.NetServices _netServices = new Data.NetServices(_connString);
Data.ProductOption[] test = new Data.ProductOption[]
{
new Data.ProductOption
{
Name="TEST1",
//Notice the assignment here
ProductOptionCategory=_netServices.ProductOptionCategory.First(poc => poc.Name == "laminate")
}
};
_netServices.SubmitChanges();
Running the code above will insert a new row in the database. I noticed this effect while writing an app to parse an XML file and populate some tables. I noticed there were 1000+ inserts when I was only expecting around 50 or so - then I finally isolated this behavior.
How can I prevent these objects from being persisted implicitly?
Thanks,
-Charles
Think of the relationship as having two sides. When you set one side of the relationship the other side needs to be updated so in the case above as well as setting the ProductOptionCategory it is effectively adding the new object to the ProductOptions relationship on the laminate ProductOptionCategory side.
The work-around is as you have already discovered and to set the underlying foreign key instead so LINQ to SQL will not track the objects in the usual way and require implicit indication it should persist the object.
Of course the best solution for performance would be to determine from the source data which objects you don't want to add and never create the instance in the first place.