Best approach to load a dettached collection - entity-framework-4.1

I have a disconnected entity called "Establishment" which has a collection called "Locations".
What's the best approch to load this collection ?
I'm doing this:
var estab = new Establishment(){ ID = 1 };
Context.Establishment.Attach(estab);
Entry(estab).Collection(c => c.Locations).Load();
The problem is that, I'm testing this code on linqpad and it generates one sql text for each Location row (oh my!)

Just disable Lazy Loading
Context.Configuration.LazyLoadingEnabled = false;

Related

Symfony 3.4 : how to log the history of user actions?

I want to store in my database all the user actions done about an entity.
For example, for 1 entity, I want to store :
Created by (= author)
Updated by
Date of creation
Date of update
I want to store the history of the actions of a user, not the last ones. I thought I could create a table with these columns :
log_id
user_id
entity_id
action (= "create" or "update" or something else)
date
And then, I could easily get the last update of my entity and display the date and the user who did it.
Is there a Symfony bundle to do this ? Should I use Monolog ?
I will do this for many entities and I'm not sure if this is the correct way to do...
Is it possible to create only one logs table to store each log about each entity ? It bothers me to create 1 logs table per entity.
Since Doctrine is event based, it's easy:
Either use an extension, like Gedmo Loggable
Or hook into Doctrine's events and log, using Monolog, everything that happens in your app.
Personally I would prefer option 2 since I'm a control maniac, it's a little more complex though. Personally I would also use Monolog so I could abstract away the way how and where the log entries are stored.
When you decide how to approach this and you will need any assistance along the way, please ask another question.
Good luck.
I don't know if that would fit what you need, but you could easily add a Listener to the symfony kernel to log every controller used.
Something like this :
class UserLogListener {
protected $authChecker;
protected $tokenStorage;
protected $entityManager;
public function __construct(TokenStorageInterface $tokenStorage, AuthorizationChecker $authChecker, EntityManager $entityManager)
{
$this->authChecker = $authChecker;
$this->tokenStorage = $tokenStorage;
$this->entityManager = $entityManager;
}
public function onKernelRequest(GetResponseEvent $event)
{
if( $this->tokenStorage->getToken() != null){
$user = $this->tokenStorage->getToken()->getUser();
$currentDate = new \Datetime();
$action = $event->getRequest()->attributes->get('_controller');
$method = $event->getRequest()->getMethod();
$userIp = $event->getRequest()->getClientIp();
$userLogRepository = $this->entityManager->getRepository(UserLog::class);
if($user instanceof User){
$userLog = new UserLog();
$userLog->setUser($user);
$userLog->setIp($userIp);
$userLog->setAction($action);
$userLog->setMethode($method);
$userLog->setDate($currentDate);
if($event->getRequest()->request && $methode=='POST'){
$userLog->setData(json_encode($event->getRequest()->request->all()));
}else{
$userLog->setData($event->getRequest()->getPathInfo());
}
$this->entityManager->persist($userLog);
$this->entityManager->flush();
}
}
}
}
What it does is add to the database (with an entity called UserLog) information about every page called. So you can know which action is made by knowing which controller is called, and you can also log the request data so you can find out what modification/creation the user did.

How can I have the name of my entity instead of the id in the related tables

I'm creating a project on CakePHP 3.x where I'm quite new. I'm having trouble with the hasMany related tables to get the name of my entities instead of their ids.
I'm coming from CakePHP 2.x where I used an App::import('controller', array('Users') but in the view to retrieve all data to display instead of the ids, which is said to be a bad practice. And I wouldn't like to have any code violation in my new code. Can anybody help me? here is the code :
public function view($id = null)
{
$this->loadModel('Users');
$relatedUser = $this->Users->find()
->select(['Users.id', 'Users.email'])
->where(['Users.id'=>$id]);
$program = $this->Programs->get($id, [
'contain' => ['Users', 'ProgramSteps', 'Workshops']
]);
$this->set(compact('program', 'users'));
$this->set('_serialize', ['ast', 'relatedUser']);
}
I expect to get the user's email in the relatedUsers of the program table but the actual output is:
Notice (8): Trying to get property 'user_email' of non-object [APP/Template\Asts\view.ctp, line 601].
Really need help
Thank you in advance.
You've asked it to serialize the relatedUser variable, but that's for JSON and XML views. You haven't actually set the relatedUser variable for the view:
$this->set(compact('program', 'users', 'relatedUser'));
Also, you're setting the $users variable here, but it's never been initialized.
In addition to #Greg's answers, the variable $relateduser is still a query object, meaning that trying to access the email property will fail. The query still needs to be executed first.
You can change the query to:
$relatedUser = $this->Users->find()
->select(['Users.id', 'Users.email'])
->where(['Users.id' => $id])
->first();
Now the query is executed and the only the first entry is returned.
There is are a number of ways to get a query to execute, a lot of them are implicit is use. See:
Cookbook > Retrieving Data & Results Sets

Why Are My CakePHP AROs Not Being Created?

I followed the CakePHP Cookbook's simple ACL application tutorial and for a while all way fine and dandy. When I created a user, my AROs were automagically created too, and without too much effort I was able to give everyone permissions for the correct actions.
My application has become more complex now though. When I create a "Realtor", I create a user for them in the Realtor model's afterSave function, like so:
App::import( 'Component', 'Auth' );
$this->Auth = new AuthComponent();
$this->User->create();
$this->User->set(array(
'username' => $this->data['Realtor']['email'],
'password' => $this->Auth->password($this->data['Realtor']['password']),
'usergroup_id' => 2,
'realtor_num' => $this->id
));
if ($this->User->save()) {
$this->save(array('user_id'=>$this->User->id));
} else {
//error
}
Unfortunately, while this is successfully creating users, and the data all seems to match up with my expectations, I'm seemingly no longer getting AROs.
My Usergroup model contains the line
var $actsAs = array('Acl' => array('type' => 'requester'));
Beyond that, I have no idea how I would persuade my application to generate an ARO.
Is there anything I could have forgotten, that would help me get my ACL back on track?
EDIT:
I had this in the User model's afterSave which seems to have been causing various kinds of trouble:
function afterSave($created) {
if (!$created) {
$parent = $this->parentNode();
$parent = $this->node($parent);
$node = $this->node();
$aro = $node[0];
$aro['Aro']['parent_id'] = $parent[0]['Aro']['id'];
$this->Aro->save($aro);
}
}
(courtesy of this article: http://mark-story.com/posts/view/auth-and-acl-automatically-updating-user-aros) I don't know if that would have been fouling up my ARO creation somehow... probably teach me to add in random code snippets without fully understanding what they're doing, at the very least!
Ok I' m newbie
I can't understand your problem but
now I use Acl component with alaxos acl plugin
I try to understand of modified tree traversal algorithm
and set basic data for aro,aco,aro_aco,group table
and some requirement of plugin
I suggest you to use this

Is good practice create a controller for auto-complete filters?

I'm a newbie in asp.net mvc.
I need to create a 'auto-complete tag search' functionality like stackoverflow. My intent is to create a controller with JsonResult to get a filtered tag to auto-complete the input-text element. This is a good practice? If yes, any recommendations for something I need to avoid?
Thanks in advance.
PS.: Sorry for poor English.
The solution suggested by kekekela can be used even if there are multiple filter parameters, no need to create multiple actions unless the result set is of different type. For example:
[HttpPost]
[Authorize]
public JsonResult FilterTasks(int maxResults, string users = "", string tags = "", string categories = "")
{
List<int> userIdList = MyHelper.GetIntList(users);
List<string> tagNameList = MyHelper.GetStringList(tags);
List<string> categoryIdList = MyHelper.GetStringList(categories);
var tasks = from task in projectsEntities.Tasks select task;
if (userIdList.Count > 0)
tasks = tasks.Where(task => userIdList.Contains(task.UserId));
if (tagNameList.Count > 0)
tasks = tasks.Where(task => tagNameList.Contains(task.TagName));
if (categoryIdList.Count > 0)
tasks = tasks.Where(task => categoryIdList.Contains(task.CategoryId));
var topTasks = tasks.Take(maxResults).ToArray();
return Json(topTasks);
}
If you mean a controller action then yes, this is how I've done it. You could add a new controller but typically I've just added a method to an existing controller where it makes sense to do so.
I don't know of a reason to bypass controllers at all! They ensure your calls follow a pattern. I've never gone back to straight php, asp, or jsp pages since I've started using MVC packages, keeps the code so nice and separated according to concerns.

LINQ 2 SQL Query ObjectDisposed Exception

This one i had today is a strange one.
I have this query in an assembly method.
public Order[] SelectAllOrders()
{
Order[] orders;
using (MyDataContext context = new MyDataContext())
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Order>(order => order.OrderDetails);
context.LoadOptions = dlo;
orders = context.Orders.Select(p => p).ToArray();
}
return orders;
}
Supposed i already called the ToArray() the SQL Command executed and gave me the objects i need and i give them to a new Order[] array this should not need the DataContext instance.
While im serializing the Order[] i get from the method return, serializer tries to access the DataContext again and i get an exception that cannot access disposed object.
Tried without the using() statement and works like it should. But, why i get this behavior?
Anyone could give an explanation why deferred loading still remains while I'm calling .ToArray() and assigning new variable with the contents?
The Select(p=>p) achieves very little; you might as well just call:
orders = context.Orders.ToArray();
Re the problem - I would guess that either OrderDetails hasn't really loaded, or it is trying to load some other data lazily. I would suggest investigating by (in a dev session):
Order[] orders;
using (MyDataContext context = new MyDataContext())
{
context.Log = Console.Out; // show me
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Order>(order => order.OrderDetails);
context.LoadOptions = dlo;
Console.WriteLine("> Calling ToArray");
orders = context.Orders.ToArray();
Console.WriteLine("> ToArray complete");
// TODO: your extra code that causes serialziation, probably
// involving `DataContractSerializer`
Console.WriteLine("> Calling Dispose");
}
With this, you should be able to see any extra database trips that are happning after the ToArray but before the Dispose(). The point being: this data is needed for serialization, so either a: ensure it gets loaded, or b: exclude it from serialization.