HasOne relationship returns null on save - laravel-5.3

I have two models A and B with a foreign key on A of b_id on the id of B. the model code is as follows
A has a trait BB with the following methods
public function b() // shared by multiple models
{
return $this->hasOne(B::class, 'id', 'b_id'); // table has foreign keys setup
}
public function saveB($params){
$b = $this->b;
if(is_null($b)) $b = new B;
else $b->a()->dissociate($b->id); // if there is a b break the link between them
if($b->setParams($params) === true)
{
try {
$this->b()->save($b);
$this->save();
} catch (Exceptio ....... throw an exception if anything
}
B is a model with the method
public method setParams($params) {
$this->trigger = $params[0];
$this->colour = $params[1];
.... arbitrary stuff not related;
}
The problem arises out of the following TestCase logic
public function setUp()
{
parent::setUp();
$this->a = A::find(237); // actual record
$this->a->saveB(['trigger'=>1,'colour'=>'orange']);
}
public function testSaveB(){
$this->assertGreaterThan(0, $this->a->b_id);
}
The assertGreaterThan test fails and the b_id is null even though the following is true
The table foreign keys exists
Appropriate fields are fillable
The data for B is inserted( no previous record existed)
The record exists and b_id was NULL from inception
No exceptions are thrown
Note the model names have been changed to make things easier to understand but the functions are more or less exactly as I have it
Does this logic model->hasOne()->save(model) inserts the newly created model and updates the foreign key for it? or do i have to still update the key/ value and $a->update() rather than $a->save()?

Related

Running a SELECT on a specific column that matches an input from kotlin function, throws null pointer

I am trying to write a method that takes a username as its input and creates a SQL query statement which is then executed. As of right now, I am getting a NullPointer when I try to call result.getObject().
Here is my method for creating the SQL statement dynamically:
fun getByUsername(name: String): User?{
val sql = """SELECT * FROM usertable WHERE username="$name";"""
val result = DatabaseController().trySql(sql)
if (result != null) {
if (!result.isBeforeFirst) {
println("User was not found...")
return null
} else {
println("User found....")
return User(result.getObject("username").toString(),
result.getObject("password").toString(),
result.getObject("admin").toString().toBoolean())
}
}
return null
}
Method that executes query:
fun trySql(sqlCommand: String): ResultSet? {
var conn = this.connect()
println("trySql()-------Running query $sqlCommand")
var result = conn?.createStatement()?.executeQuery(sqlCommand)
conn?.close()
return result
}
The username I am running it on is in my table too, so that is not the issue. My method that creates a row in my table is working properly, so I know there is no issue with connecting to the database.
EDIT
If I just return result in trySql(), I no longer get any errors, but from my reading I am supposed to close connections after use?
Why you are having issues
You are closing the connection, which makes the ResultSet you get back no longer useful. You will have access to the result object, but the result object will be unable to read data from SQLite, leading to errors.
How to fix
You can pass some code to your trySql function, which will be performed with the connection still open, and then close after the passed block.
Example
Library
class Con(val con: Connection = DriverManager.getConnection(URL)): AutoCloseable by con {
fun <T> withSQL(query: String, block: (ResultSet)->T): T {
con.createStatement().use { statement ->
statement.executeQuery(query).use { results ->
return block(results)
}
}
}
}
Usage
Con().use { con ->
val result: Int = con.withSQL("SELECT * from example WHERE name='test'") {
it.getInt(1)
}
}

JSON Lists not removing duplicates with Distinct command

Currently I am querying a web service that returns a JSON string.
url = #"redacted url;
returnValue = new WebClient().DownloadString(url);
I am putting the return results into a list of items defined in a model class. I am then running a second JSON call searching a different field with that same search term.
url2 = #"redacted url2;
returnValue2 = new WebClient().DownloadString(url2);
I then create my lists and combine the lists using AddRange.
List<Order> shipments = JsonConvert.DeserializeObject<List<Order>>(returnValue);
List<Order> shipments2 = JsonConvert.DeserializeObject<List<Order>>(returnValue2);
shipments.AddRange(shipments2);
As a result there are some duplicates. To try and only return unique records I am using the command Distinct when sending to my MVC view from the controller.
return View(shipments.OrderBy(x => x.dtDateReceived).Distinct().ToList());
But for some reason it's still returning duplicates.
Any ideas on what I am doing wrong here?
Thanks in advance for any help!
I ended up correcting it using Shyju's comment above.
I changed the Distinct to the following.
return View(shipments.OrderBy(x => x.dtDateReceived).Distinct(new OrderComparer()).ToList());
Then built the following compare functions
// Custom comparer for the Order class
class OrderComparer : IEqualityComparer<Order>
{
// Orders are equal if their names and order numbers are equal.
public bool Equals(Order x, Order y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the order's properties are equal.
return x.sWorkOrderNumber == y.sWorkOrderNumber && x.sCustomerOrderName == y.sCustomerOrderName;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Order order)
{
//Check whether the object is null
if (Object.ReferenceEquals(order, null)) return 0;
//Get hash code for the sCustomerOrderName field if it is not null.
int hashOrderName = order.sCustomerOrderName == null ? 0 : order.sCustomerOrderName.GetHashCode();
//Get hash code for the sWorkOrderNumber field.
int hashOrderCode = order.sWorkOrderNumber.GetHashCode();
//Calculate the hash code for the order.
return hashOrderName ^ hashOrderCode;
}
}

WF 4 Rehosted Designer - get foreach InArgument Value

After reading this article:
http://blogs.msdn.com/b/tilovell/archive/2009/12/29/the-trouble-with-system-activities-foreach-and-parallelforeach.aspx
I have defined the ForEachFactory as follows:
public class ForEachFactory<T> : IActivityTemplateFactory
{
public Activity Create(DependencyObject target)
{
return new ForEach<T>
{
DisplayName = "ForEachFromFactory",
Body = new ActivityAction<T>
{
Argument = new DelegateInArgument<T>("item")
}
};
}
}
All works well but is it possible to check how that DelegeateInArgument in my case named "item" changes its value ?
So if i have defined an array in the variables section and initialized with
{1, 2, 3} i need a way to check how the "item" takes value 1, 2 and then 3.
To be more accurate, i've added this pic, with a breakpoint on the WriteLine activity inside the foreach. When the execution will stop there, is there a way to find out what the value of item is ?
EDIT 1:
Possible solution in my case:
After struggling a bit more i found one interesting thing:
Adding one of my custom activities in the Body of the ForEach, i am able to get the value of the item like this :
So, my activity derives from : CodeActivity
Inside the protected override String[] Execute(CodeActivityContext context) i am doing this job.To be honest, this solves the thing somehow, but it is doable only in my custom activities. If i would put a WriteLine there for example, i would not be able to retrieve that value.
you can access the DelegeateInArgument of a ForEach activity by inspecting the ModelItem trees parent and checking for DelegeateInArgument's. If you need a specific code example to achieve this I may need a some time to code the example. As it has been a long time since I did this, see my question i asked over on msdn
So basically where your break point is, you can access the variable values as these are defined with n the scope of your activity as 'variables'. However the 'item' variable is actually only accessible from the parent loop activity. So you have to get the model item of the current executing activity and then traverse up the tree to find the parent containing the desired DelegateInArgument.
Can you flesh out exactly what you want to achieve? Is it that when your debugging the workflow in the re-hosted designer you want to display the variable values to the user as they change in the UI?
Edit - added tracking example
So as your wanting to display the variable values during execution of the workflow we need to use tracking to achieve this. In the example your using the author has already implemented some basic tracking. So to achieve the extended variable tracking you want you will need to alter the tracking profile.
Firstly amend the WorkflowDesignerHost.xaml.cs file alter the RunWorkflow method to define the SimulatorTrackingParticipant as below.
SimulatorTrackingParticipant simTracker = new SimulatorTrackingParticipant()
{
TrackingProfile = new TrackingProfile()
{
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
**States = {all },**
},
new ActivityStateQuery()
{
// Subscribe for track records from all activities for all states
ActivityName = all,
States = { all },
**Arguments = {all},**
// Extract workflow variables and arguments as a part of the activity tracking record
// VariableName = "*" allows for extraction of all variables in the scope
// of the activity
Variables =
{
{ all }
}
}
}
}
};
This will now correctly capture all workflow instance states rather than just Started/Completed. You will also capture all Arguments on each activity that records tracking data rather than just the variables. This is important because the 'variable' were interested in is actually (as discussed earlier) a DelegateInArgument.
So once we have changed the tracking profile we also need to change the SimulatorTrackingParticipant.cs to extract the additional data we are now tracking.
If you change the OnTrackingRecordReceived method to include the following sections these will capture variable data and also Argument data during execution.
protected void OnTrackingRecordReceived(TrackingRecord record, TimeSpan timeout)
{
System.Diagnostics.Debug.WriteLine(
String.Format("Tracking Record Received: {0} with timeout: {1} seconds.", record, timeout.TotalSeconds)
);
if (TrackingRecordReceived != null)
{
ActivityStateRecord activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
IDictionary<string, object> variables = activityStateRecord.Variables;
StringBuilder vars = new StringBuilder();
if (variables.Count > 0)
{
vars.AppendLine("\n\tVariables:");
foreach (KeyValuePair<string, object> variable in variables)
{
vars.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", variable.Key, variable.Value));
}
}
}
if (activityStateRecord != null)
{
IDictionary<string, object> arguments = activityStateRecord.Arguments;
StringBuilder args = new StringBuilder();
if (arguments.Count > 0)
{
args.AppendLine("\n\tArgument:");
foreach (KeyValuePair<string, object> argument in arguments)
{
args.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", argument.Key, argument.Value));
}
}
//bubble up the args to the UI for the user to see!
}
if((activityStateRecord != null) && (!activityStateRecord.Activity.TypeName.Contains("System.Activities.Expressions")))
{
if (ActivityIdToWorkflowElementMap.ContainsKey(activityStateRecord.Activity.Id))
{
TrackingRecordReceived(this, new TrackingEventArgs(
record,
timeout,
ActivityIdToWorkflowElementMap[activityStateRecord.Activity.Id]
)
);
}
}
else
{
TrackingRecordReceived(this, new TrackingEventArgs(record, timeout,null));
}
}
}
Hope this helps!

AutoMapper: Can't access original object instances passed to Map() from within AfterMap()

I have code like this:
//Fields
Product _prod, _existingProd;
void Test()
{
_prod = MakeAndPopulateSomeRandomProduct();
_existingProd = GetProdFromDb(1);
Mapper.CreateMap()
.AfterMap((s, d) =>
{
Console.WriteLine(d==_existingProd); //Why does this print false?
//Customize other properties on destination object
});
Mapper.Map(_prod, _existingProd);
}
When I call Test(), false is printed but I expected true. In my scenario, it is important to be able to access the original destination object via the AfterMap argument. I only included the fields to demonstrate the problem but in my real code, I don't have direct access to them. How can I access the object instances passed in to Map() when customizing the mapping?
The following example works. Probably you are using some type converter which creates new instance... Also please provide all mapping configurations to better understand the problem.
[TestFixture]
public class AfterMap_Test
{
//Fields
private Product _prod, _existingProd;
[Test]
public void Test()
{
Mapper.CreateMap<Product, Product>()
.AfterMap((s, d) =>
{
Trace.WriteLine(d == _existingProd); //Why does this print false?
//Customize other properties on destination object
});
_existingProd = new Product {P1 = "Destination"};
_prod = new Product {P1 = "Source"};
Mapper.Map(_prod, _existingProd);
}
}
internal class Product
{
public string P1 { get; set; }
}

Picking out Just JSON Data Returned from ASP.NET MVC3 controller Update

I've got data returned from my JavaScript client that just includes the data that has changed. That is, I may have an array with each row containing 10 columns of JSON downloaded, but on the Update, only the data that is returned to me is the data that got updated. On my update, I only want to update those columns that are changed (not all of them).
In other words, I have code like below but because I'm passing in an instance of the "President" class, I have no way of knowing what actually came in on the original JSON.
How can I just update what comes into my MVC3 update method and not all columns. That is, 8 of the columns may not come in and will be null in the "data" parameter passed in. I don't want to wipe out all my data because of that.
[HttpPost]
public JsonResult Update(President data)
{
bool success = false;
string message = "no record found";
if (data != null && data.Id > 0)
{
using (var db = new USPresidentsDb())
{
var rec = db.Presidents.FirstOrDefault(a => a.Id == data.Id);
rec.FirstName = data.FirstName;
db.SaveChanges();
success = true;
message = "Update method called successfully";
}
}
return Json(new
{
data,
success,
message
});
}
rec.FirstName = data.FirstName ?? rec.FirstName;
I would use reflection in this case because the code will be too messy like
if (data.FirstName != null)
rec.FirstName = data.FirstName
.
.
.
and so on for all the fields
Using reflection, it would be easier to do this. See this method
public static void CopyOnlyModifiedData<T>(T source, ref T destination)
{
foreach (var propertyInfo in source.GetType().GetProperties())
{
object value = propertyInfo.GetValue(source, null);
if (value!= null && !value.GetType().IsValueType)
{
destination.GetType().GetProperty(propertyInfo.Name, value.GetType()).SetValue(destination, value, null);
}
}
}
USAGE
CopyOnlyModifiedData<President>(data, ref rec);
Please mind that, this won't work for value type properties.

Resources