Lumen Eloquent Relations - eloquent

UPDATE
My approach is to receive something equal to a simpel mysql join. I want all entries from tabel tx with project_id = x joined with txevent on tx.id = txevent.tx_id.
I´m using lumen 5.5
UPDATE 2
The following raw sql will do exactly what I want:
$rawTx = DB::>table('tx')
->join('txevent', 'txevent.tx_id', '=', 'tx.id')
->where('tx.project_id', $request->get('project_id'))
->where('txevent.short_id', $request->get('short_id'))
->get();
Isn´t it possible to achieve the same with relations?
END UPDATE
I´ve got 2 tables tx and txevent:
tx:
id, int, autoincrement
project_id, int
txevent:
id, int, autoincrement
tx_id, int, fk(tx.id)
shortnumber, char
in tx.php I´ve got the following method:
public function txeventWithShortnumber($shortnumber)
{
return $this->hasOne('App\Txevent')->where('shortnumber', $shortnumber)->first();
}
in TxController.php I´ll do:
$tx = Tx::where('project_id', $request->get('project_id'))->txeventWithShortnumber($request->get('shortnumber'))->get();
as result I get the following error message:
(1/1) BadMethodCallException
Call to undefined method Illuminate\Database\Query\Builder::txeventWithShortnumber()
in Builder.php line 2483
Can someone tell me what I´m doing wrong?

I recommend to do it this way:
In Tx.php
public function txEvents()
{
return $this->hasMany(TxEvent::class);
}
public function txeventWithShortnumber($shortNumber)
{
return $this->txEvents->first(function($txevent) use ($shortNumber) {
return $txevent->shortnumber == $shortNumber;
});
}
In controller:
$tx = Tx::where('project_id', $request->get('project_id'))->get();
// attach shortNumber event
$tx->map(function($t) use ($request) {
$t->eventWithShortNumber = $t->txeventWithShortnumber($request->get('shortnumber'));
});
$tx variable will now hold txEvents with the given short number as well.
I am not sure if you can dynamically pass condition to an eloquent relationship.

Related

Force Entity Framework to read each line with all details

I am having trouble with en EF method returning duplicate rows of data. When I am running this, in my example, it returns four rows from a database view. The fourth row includes details from the third row.
The same query in SSMS returns four individual rows with the correct details. I have read somewhere about EK and problems with optimization when there are no identity column. But - is there anyway to alter the below code to force EK to read all records with all details?
public List<vs_transactions> GetTransactionList(int cID)
{
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}
Found the solution :) MergeOption.NoTracking
public List<vs_transactions> GetTransactionList(int cID)
{
db.vs_transactions.MergeOption = MergeOption.NoTracking;
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}

Understanding issue get one row from database with 2 parameters

I thought it would work find, but it doesn't.
I have a method in my modelclass like this:
public function getUnitbyName2($unitname, $ProjectID)
{
//$id = (int) $id;
$rowset = $this->tableGateway->select(['Unitname' => $unitname], ['ProjectID' => $ProjectID]);
$row = $rowset->current();
if (! $row) {
// throw new RuntimeException(sprintf(
// 'Could not find row with identifier %d',
// $unitname
// ));
$row=0;
}
return $row;
}
If I give an existing unitname and a non existent project_ID I expect to get some 0 value. But I always get the number of the unit in the first project with the given unitname. It is common that the unitname exists in several different projects.
The function is supposed to get the right record if exist using both parameters.
My question is, what's wrong with using 2 parameters connected by AND?
AbstractTableGateway::select() accepts one argument, you are passing 2:
You need to pass 1, combine the 2 arrays.
Change your code to:
$rowset = $this->tableGateway->select(['Unitname' => $unitname, 'ProjectID' => $ProjectID]);
Zend table Gateways

How to obtain a subset of records within a context using EntityFramework?

A newbie question. I am using EntityFramework 4.0. The backend database has a function that will return a subset of records based on time.
Example of working code is:
var query = from rx in context.GetRxByDate(tencounter,groupid)
select rx;
var result = context.CreateDetachedCopy(query.ToList());
return result;
I need to verify that a record does not exist in the database before inserting a new record. Before performing the "Any" filter, I would like to populate the context.Rxes with a subset of the larger backend database using the above "GetRxByDate()" function.
I do not know how to populate "Rxes" before performing any further filtering since Rxes is defined as
IQueryable<Rx> Rxes
and does not allow "Rxes =.. ". Here is what I have so far:
using (var context = new EnityFramework())
{
if (!context.Rxes.Any(c => c.Cform == rx.Cform ))
{
// Insert new record
Rx r = new Rx();
r.Trx = realtime;
context.Add(r);
context.SaveChanges();
}
}
I am fully prepared to kick myself since I am sure the answer is simple.
All help is appreciated. Thanks.
Edit:
If I do it this way, "Any" seems to return the opposite results of what is expected:
var g = context.GetRxByDate(tencounter, groupid).ToList();
if( g.Any(c => c.Cform == rx.Cform ) {....}

Generate dynamic select lambda expressions

I am somewhat new to expression trees and I just don't quite understand some things.
What I need to do is send in a list of values and select the columns for an entity from those values. So I would make a call something like this:
DATASTORE<Contact> dst = new DATASTORE<Contact>();//DATASTORE is implemented below.
List<string> lColumns = new List<string>() { "ID", "NAME" };//List of columns
dst.SelectColumns(lColumns);//Selection Command
I want that to be translated into code like this (Contact is an entity using the EF4):
Contact.Select(i => new Contact { ID = i.ID, NAME = i.NAME });
So let's say I have the following code:
public Class<t> DATASTORE where t : EntityObject
{
public Expression<Func<t, t>> SelectColumns(List<string> columns)
{
ParameterExpression i = Expression.Parameter(typeof(t), "i");
List<MemberBinding> bindings = new List<MemberBinding>();
foreach (PropertyInfo propinfo in typeof(t).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (columns.Contains(propinfo.Name))
{
MemberBinding binding = Expression.Bind(propinfo, Expression.Property(i, propinfo.Name));
bindings.Add(binding);
}
}
Expression expMemberInit = Expression.MemberInit(Expression.New(typeof(t)), bindings);
return Expression.Lambda<Func<t, t>>(expMemberInit, i);
}
When I ran the above code I got the following error:
The entity or complex type 'Contact' cannot be constructed in a LINQ to Entities query.
I looked at the body of the query and it emitted the following code:
{i => new Contact() {ID = i.ID, NAME = i.NAME}}
I am pretty sure that I should be able to construct the a new entity because I wrote this line explicitly as a test to see if this could be done:
.Select(i => new Contact{ ID = i.ID, NAME = i.NAME })
This worked, but I need to construct the select dynamically.
I tried decompiling a straight query(first time I have looked at the low level code) and I can't quite translate it. The high level code that I entered is:
Expression<Func<Contact, Contact>> expression = z =>
new Contact { ID = z.ID, NAME = z.NAME };
Changing the framework used in the decompiler I get this code:
ParameterExpression expression2;
Expression<Func<Contact, Contact>> expression =
Expression.Lambda<Func<Contact, Contact>>
(Expression.MemberInit(Expression.New((ConstructorInfo) methodof(Contact..ctor),
new Expression[0]), new MemberBinding[] { Expression.Bind((MethodInfo)
methodof(Contact.set_ID), Expression.Property(expression2 = Expression.Parameter(typeof(Contact), "z"), (MethodInfo)
methodof(Contact.get_ID))), Expression.Bind((MethodInfo)
methodof(Contact.set_NAME), Expression.Property(expression2, (MethodInfo)
methodof(Contact.get_NAME))) }), new ParameterExpression[] { expression2
});
I have looked several places to try and understand this but I haven't quite gotten it yet. Can anyone help?
These are some places that I have looked:
msdn blog -- This is exactly what I want to do but my decopiled code soes not have Expression.Call.
msdn MemberInit
msdn Expression Property
stackoverflow EF only get specific columns -- This is close but this seems like it is doing the same thing as if i just use a select off of a query.
stackoverflow lambda expressions to be used in select query -- The answer here is exactly what I want to do, I just don't understand how to translate the decompiled code to
C#.
When I did it last time I projected result to not mapped class (not entity) and it worked, everything else was the same as in your code. Are you sure that not dynamic query like .Select(i => new Contact{ ID = i.ID, NAME = i.NAME }) works?

Scalar Value from stored procedure via Entity Framework

I have found a few articles like this one:
http://devtoolshed.com/using-stored-procedures-entity-framework-scalar-return-values
Yet when I take the step to create a function import for a int32 scalar, this is what gets generated:
public ObjectResult<Nullable<global::System.Int32>> MyStoredProcedure(Nullable<global::System.Int32> orderId)
{
ObjectParameter orderIdParameter;
if (orderId.HasValue)
{
orderIdParameter = new ObjectParameter("OrderId", orderId);
}
else
{
orderIdParameter = new ObjectParameter("OrderId", typeof(global::System.Int32));
}
return base.ExecuteFunction<Nullable<global::System.Int32>>("MyStoredProcedure", orderIdParameter);
}
I am able to call the procedure with this, but am not able to get to the underlying scalar:
ObjectResult<int?> result = myEntities.MyProcedure(orderId);
In the code examples I have seen, I should get context.MyProcedure().SingleOrDefault().
Try this:
int? result = myEntities.MyProcedure(orderId).FirstOrDefault();