I'm using: ASP.NET MVC, MySql, Dapper.NET micro-orm
I made a stored procedure with 3 SELECTs, two of which returns lists and the third one returns an integer.
Here is my code:
using (var conn = new MySqlConnection(GetConnectionString()))
{
var readDb = conn.QueryMultiple(storedProcedure, parameters, commandType: CommandType.StoredProcedure);
var result = new someView
{
TopicsList = readDb.Read<ITopic>().ToList(),
TopTopicsList = readDb.Read<IMessage>().ToList(),
TopicsCount = readDb.Read<int>().Single()
};
return result;
}
In ITopic I have TopicId, in IMessage I have MessageId.
And here's the error:
When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id Parameter name: splitOn
I tried adding splitOn on both QueryMultiple and Read, and nigher accepted it.
Though I dont understand why I need splitOn? can't dapper see that I have three separate SELECTs? When using conn.Read(storedProcedure,parameters) on each of the selects separately (instead of MultipleQuery on all of the together) dapper has no problem mapping it to a given object.
What am I doing wrong?
1) Problem solved when I used the real models names instead of their interfaces names:
TopicView instead of ITopic, TopTopicsView instead of IMessage;
2) Once that was fixed and there was no longer "no splitOn" error, started another problem with the < int > casting in line:
TopicsCount = readDb.Read<int>().Single()
probably mysql doesnt return numbers back as ints?
I tried using decimal, object, dynamic, etc.. with no luck. Eventually fixed it by creating another Model with int property inside that has the same name as the database int parameter and now it works.
3) Here's the final working code:
using (var conn = new MySqlConnection(GetConnectionString()))
{
var parameters = context.MapEntity(query);
var multi = conn.QueryMultiple(storedProcedure, parameters, commandType: System.Data.CommandType.StoredProcedure);
var TopicsList = multi.Read<TopicView>().ToList();
var TopTopicsList = multi.Read<TopTopicsView>().ToList();
var result = multi.Read<HomeView>().Single();
result.TopicsList = TopicsList;
result.TopTopicsList = TopTopicsList;
return result;
}
Related
I am working with two collections of satellite data. I want to select specific bands from "collection 1", join them to "collection 2", and then run a function. Unfortunately, the function does not work with the joined data, although it works for "collection 1".
Here is an example just using B10 of Sentinel-2
//identifying area and date
var geometry = ee.Geometry.Point([4,45]);
Map.centerObject(geometry,10);
var start = '2019-03-10';
var end = '2019-05-10';
//my function
function testing(img){
img = img.updateMask(img.select(['B10']).gt(200).focal_min(2).focal_max(2).not());
return img;
}
//my two collections
var collection1 = ee.ImageCollection('COPERNICUS/S2').filterDate(start,end)
.filterBounds(geometry);
var B10s=collection1.select('B10');
//print('B10s',B10s);
var collection2 = ee.ImageCollection('COPERNICUS/S2_SR')
.filterDate(start,end)
.filterBounds(geometry);
// joining the collections
var filtering = ee.Filter.equals({
leftField: 'system:time_start',
rightField: 'system:time_start'
});
var simpleJoin = ee.Join.inner();
var innerJoin = simpleJoin.apply(collection2, B10s, filtering);
var joined = innerJoin.map(function(feature) {
return ee.Image.cat(feature.get('primary'), feature.get('secondary'));
});
print('Joined', joined);
//just to visualize one image
//var coll1 = ee.Image(collection1.first());
//Map.addLayer(coll1, {bands:['B2'], min:0, max:5000},'B2Coll1 test');
//running the function for collection 1 works
var test = collection1.map(testing);
var tess = ee.Image(test.first());
Map.addLayer(tess, {bands:['B2'], min:0, max:5000},'B2 test');
//here when running with the joined collection, there is a problem
var TestingJoined = joined.map(testing);
The error is: img.select(...).gt is not a function
How do I make this work?
When you debug, does the join work as intended? Is there any issue with the datetimes being too-precise to allow a full join?
The second route I would go down is ensuring that the joined object is identical to collections. I doubt this would be the case without you casting it or something (though I'm not familiar with this library). Your "testing" function that you're mapping to these collections may work with just the unjoined ones. If you provide the actual 'Problem' or error output that would be immensely helpful.
Ok. I solved it. Thank you for your input.
I needed to use a cast in the function. Now it works.
function testing(img){
img = ee.Image(img).updateMask(ee.Image(img).select(['B10']).gt(200).focal_min(2).focal_max(2).not());
return img;
}
This relates to some older questions on SuiteScript 1.0. I've got a 2.0 script that has to be 2.0, so I can't use the old nlapiGetLineItemValue - it has to be Record.getSublistValue(options). But I need it to get the line value on a new, unsaved record BeforeSubmit.
It keeps returning "getSublistValue" is not defined in object, and checking NetSuite Field Explorer confirms that the unsaved record has no defined lines.
The same applies to AfterSubmit.
So is there any work around, or is it even possible, to reference the line item value when the record is being created?
ADDING SOME CODE, WHERE THE QUESTION APPLIES:
var recNew = context.newRecord
var ItemID = recNew.getSublistValue({
sublistId: 'items',
fieldId: 'itemid',
});
var listIDs = ["6646", "17745", "17945", "21349"];
var a_filters = [];
a_filters.push(new nlobjSearchFilter(ItemID, null, 'anyof', listIDs));
{
// an action
}
getSublistValue requires you to pass the line number.
var recNew = context.newRecord
for (var x =0; x< recNew.getLineCount({sublistId:'item'}); x++) {
var ItemID = recNew.getSublistValue({ sublistId: 'item', fieldId: 'item', line: x });
// DO STUFF
}
try using
if(scriptContext.type == 'edit'){
var recNew = scriptContext.newRecord
recNew.getSublistValue(options)
}
Some background
I'm wanting to bind a list of objects (my model-view) to a grid. The model-view contains fields for both an specific entity and fields from a joined entity.
I was getting an error when I would try to bind due to the dbContext being out of scope. I realized I needed to use the .Include() method in order to eager load my navigation property. However, I suspect that since I'm using Linq to Entities, that I'm now generating another error:
"Unable to cast the type 'System.Linq.IQueryable1' to type 'System.Data.Objects.ObjectQuery1'. LINQ to Entities only supports casting EDM primitive or enumeration types."
My code is shown below, any ideas of what I need to do here?
Thanks in advance!
public static List<PlanViewModel> GetPlans()
{
using (var context = new RepEntities())
{
var query = (from p in context.Plans
join r in context.RealEstateDetails on p.ReId equals r.ReId
select new PlanViewModel
{
PlanName = p.PlanName,
TargetCompletionDate = p.TargetCompletionDate,
ActualCompletionDate = p.ActualCompletionDate,
Provision = p.Provision,
StatusTypeId = p.StatusTypeId,
StatusCommon = p.StatusCommon,
Building = r.BuildingName,
City = r.City,
Country = r.Country
}).Include("StatusCommon");
return query.ToList();
}
}
You are almost there, just put Include("StatusCommon") right after context.Plans. Because you need to include StatusCommon before the iteration, this way you can set StatusCommon value for every iteration.
public static List<PlanViewModel> GetPlans()
{
using (var context = new RepEntities())
{
var query = (from p in context.Plans.Include("StatusCommon")
join r in context.RealEstateDetails on p.ReId equals r.ReId
select new PlanViewModel
{
PlanName = p.PlanName,
TargetCompletionDate = p.TargetCompletionDate,
ActualCompletionDate = p.ActualCompletionDate,
Provision = p.Provision,
StatusTypeId = p.StatusTypeId,
StatusCommon = p.StatusCommon,
Building = r.BuildingName,
City = r.City,
Country = r.Country
}).toList();
return query;
}
}
Hi this is the SP I have :
USE [Tracker_Entities]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[uspHub]
#id int
AS
BEGIN
SELECT DISTINCT table1.UID, table1.url, Scope.ID
FROM table1 INNER JOIN
Scope ON table1.UID = Scope.newBrand
WHERE (table1.value = 0) AND (Scope.ID = #id)
ORDER BY table1.url
END
GO
When i run this SP in sql server by passing ID as parameter i am getting expected result. Now I need to check this SP in mvc. This is the way I am calling this SP in my MVC :
using (var ctx = new database_Entities())
{
int ID = 122;
ctx.uspHub(ID);
ctx.SaveChanges();
}
But when I put breakpoint in using statement and check for results, it is not displaying any results. I am struggling here for long time and i am not getting proper solution for this. So what are the steps in MVC to check results for SP which has select statements??
Update :
I got solution for this after using tolist. Now i am getting three results in list and i need to grab one result that is URL and pass it as input parameter.
My code :
int ID = 413;
var x = ctx.uspdHub(ID).ToList();
Here x has 3 results. I need to take one result from it.I tried doing x. but it doesn't show results after i type dot. How can i achieve this??
You have to Get the result into proper model/object.
List<YourEntity> model;
using (var ctx = new database_Entities())
{
int ID = 122;
model = ctx.uspHub(ID).toList();
//ctx.SaveChanges(); - no need to call SaveChanges
// - as you are not updating anything
}
Go through this article if you need more info. Call Stored Procedure From Entity Framework (The code above will work anyways...)
use...
using (var ctx = new database_Entities())
{
int ID = 122;
var result = ctx.uspHub(ID);
}
and add a break after the result to see whats in the result variable. Obviously, the sope of result will need to be moved, but I'm only showing here how you can see the data returned.
Try to use something like this:
using (var dataContext= new database_Entities())
{
int ID = 122;
SomeEntity[] result = dataContext.Database.SqlQuery<SomeEntity>("[dbo].[uspHub] #id",new SqlParameter("#id", ID)).ToArray();
}
It is good for me. I have used ORM EntityFramework to connect with DB.
This query produces an error No value given for one or more required parameters:
using (var conn = new OleDbConnection("Provider=..."))
{
conn.Open();
var result = conn.Query(
"select code, name from mytable where id = ? order by name",
new { id = 1 });
}
If I change the query string to: ... where id = #id ..., I will get an error: Must declare the scalar variable "#id".
How do I construct the query string and how do I pass the parameter?
The following should work:
var result = conn.Query(
"select code, name from mytable where id = ?id? order by name",
new { id = 1 });
Important: see newer answer
In the current build, the answer to that would be "no", for two reasons:
the code attempts to filter unused parameters - and is currently removing all of them because it can't find anything like #id, :id or ?id in the sql
the code for adding values from types uses an arbitrary (well, ok: alphabetical) order for the parameters (because reflection does not make any guarantees about the order of members), making positional anonymous arguments unstable
The good news is that both of these are fixable
we can make the filtering behaviour conditional
we can detect the category of types that has a constructor that matches all the property names, and use the constructor argument positions to determine the synthetic order of the properties - anonymous types fall into this category
Making those changes to my local clone, the following now passes:
// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(
Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?", new DynamicParameters(
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
) { RemoveUnused = false } ).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
Note that I'm currently using DynamicParameters here to avoid adding even more overloads to Query / Query<T> - because this would need to be added to a considerable number of methods. Adding it to DynamicParameters solves it in one place.
I'm open to feedback before I push this - does that look usable to you?
Edit: with the addition of a funky smellsLikeOleDb (no, not a joke), we can now do this even more directly:
// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
using (var conn = new System.Data.OleDb.OleDbConnection(
Program.OleDbConnectionString))
{
var row = conn.Query("select Id = ?, Age = ?",
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
).Single();
int age = row.Age;
int id = row.Id;
age.IsEqualTo(23);
id.IsEqualTo(12);
}
}
I've trialing use of Dapper within my software product which is using odbc connections (at the moment). However one day I intend to move away from odbc and use a different pattern for supporting different RDBMS products. However, my problem with solution implementation is 2 fold:
I want to write SQL code with parameters that conform to different back-ends, and so I want to be writing named parameters in my SQL now so that I don't have go back and re-do it later.
I don't want to rely on getting the order of my properties in line with my ?. This is bad. So my suggestion is to please add support for Named Parameters for odbc.
In the mean time I have hacked together a solution that allows me to do this with Dapper. Essentially I have a routine that replaces the named parameters with ? and also rebuilds the parameter object making sure the parameters are in the correct order.
However looking at the Dapper code, I can see that I've repeated some of what dapper is doing anyway, effectively it each parameter value is now visited once more than what would be necessary. This becomes more of an issue for bulk updates/inserts.
But at least it seems to work for me o.k...
I borrowed a bit of code from here to form part of my solution...
The ? for parameters was part of the solution for me, but it only works with integers, like ID. It still fails for strings because the parameter length isn't specifed.
OdbcException: ERROR [HY104] [Microsoft][ODBC Microsoft Access Driver]Invalid precision value
System.Data.Odbc. OdbcParameter.Bind(OdbcStatementHandle hstmt,
OdbcCommand command, short ordinal, CNativeBuffer parameterBuffer, bool allowReentrance)
System.Data.Odbc.OdbcParameterCollection.Bind(OdbcCommand command, CMDWrapper cmdWrapper, CNativeBuffer parameterBuffer)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, string method, bool needReader, object[] methodArguments, SQL_API odbcApiMethod)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, string method, bool needReader)
System.Data.Common.DbCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
Dapper.SqlMapper.QueryAsync(IDbConnection cnn, Type effectiveType, CommandDefinition command) in SqlMapper.Async.cs
WebAPI.DataAccess.CustomerRepository.GetByState(string state) in Repository.cs
var result = await conn.QueryAsync(sQuery, new { State = state });
WebAPI.Controllers.CustomerController.GetByState(string state) in CustomerController .cs
return await _customerRepo.GetByState(state);
For Dapper to pass string parameters to ODBC I had to specify the length.
var result = await conn.QueryAsync<Customer>(sQuery, new { State = new DbString { Value = state, IsFixedLength = true, Length = 4} });