Is it possible to get an output parameter back from the LINQ To SQL DataContext when you execute a stored procedure?
IEnumerable<Address> result =
ExecuteQuery<Address>(((MethodInfo)(MethodInfo.GetCurrentMethod())),
address, pageIndex, pageSize, totalCount);
where address, pageIndex and pageSize are input parameters, and TotalCount is an output parameter.
How can you capture the output param?
here is another attempt at doing it but again cannot get the parameter value:
[Function(Name = "Telecom.AddressSearch")]
private IEnumerable SearchAddress([Parameter(Name = "address", DbType = "varchar")] string address,
[Parameter(Name = "pageIndex", DbType = "int")] int pageIndex,
[Parameter(Name = "pageSize", DbType = "int")] int pageSize,
[Parameter(Name = "totalCount", DbType = "int")] ref int totalCount)
{
IEnumerable result = ExecuteQuery(((MethodInfo)(MethodInfo.GetCurrentMethod())), address, pageIndex, pageSize, totalCount);
return result;
}
Scott Guthrie has a blog post that describes how to get LINQ to SQL to work with stored procedures. While his post does not directly answer your question, it provides a clue to something that may work. When defining a method in a .dbml class, "LINQ to SQL maps 'out' parameters in SPROCs as reference parameters (ref keyword)." You might try and use the ref keyword and see if the totalCount gets updated.
IEnumerable r = ExecuteQuery(((MethodInfo)(MethodInfo.GetCurrentMethod())),
address, pageIndex, pageSize, ref totalCount);
Update:
I did some more research, and have found a way that should work for you. This is from an MSDN article. You would need to extend your DataContext, but that shouldn't be too big of an issue (it appears you may already be doing this). Check out the article for more information, but the basic piece is this:
[Function(Name="dbo.CustOrderTotal")]
[return: Parameter(DbType="Int")]
public int CustOrderTotal([Parameter(Name="CustomerID", DbType="NChar(5)")] string customerID, [Parameter(Name="TotalSales", DbType="Money")] ref System.Nullable<decimal> totalSales)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), customerID, totalSales);
totalSales = ((System.Nullable<decimal>)(result.GetParameterValue(1)));
return ((int)(result.ReturnValue));
}
Where 'this' is your DataContext.
Update 2:
The IExecuteResult has a ReturnValue property. It is of type Object, so you will have to cast it to get the results, but it should allow you to get the Enumerable of the results. In your case, something like this should work:
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), address, pageIndex, pageSize, totalCount);
totalCount = ((System.Nullable<decimal>)(result.GetParameterValue(3)));
return (IEnumerable<Address>)result.ReturnValue;
Related
I implemented a generic solution for using lazy loading primefaces datatables using JPA Criterea.
However I am still having some doubts with thie implemented solution whenever we deal with several Joins (say for example an entity User that has relation with other entities like Account, Address, Department.....in addition to raw type properties like: String username, Date birthdate...etc).
I tested this solution but I am having some delays while loading huge number of data (however the solution is supposed to load only a limited number of rows specified by PageSize coming from datatable), so:
How to improve the performance of this solution?
How to be sure the number of loaded data is the one specified in the Pagesize?
Can you check the count() method and tell if it counts the number of result rows without loading all the data?
And most importantly how to use this solution in order to be generic with filters coming from Search forms (I mean how to use this sae generic method and give search critereas from a search form with multi search fields)?
Please I need your answer on the above mentioned questions especially the last one.
Here is the code:
public <T extends Object> List<T> search(Class<T> type, int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters){
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<T> q = cb.createQuery(type);
Root<T> root=q.from(type);
q.select(root);
//Sorting
if (sortField != null && !sortField.isEmpty()) {
String[] sortingField = sortField.split("\\.", 2);
Path path = sortingField.length == 1 ? root.get(sortingField[0]): root.join(sortingField[0]).get(sortingField[1]);
if (sortOrder.equals(SortOrder.ASCENDING)) {
q.orderBy(cb.asc(path));
} else if (sortOrder.equals(SortOrder.DESCENDING)) {
q.orderBy(cb.desc(path));
}
}
// Filtering
Predicate filterCondition = cb.conjunction();
String wildCard = "%";
for (Map.Entry<String, String> filter : filters.entrySet()) {
String[] filterField = filter.getKey().split("\\.", 2);
Path path = filterField.length == 1 ? root.get(filterField[0]): root.join(filterField[0]).get(filterField[1]);
filterCondition = cb.and(filterCondition, filter.getValue().matches("[0-9]+")
? cb.equal(path, Long.valueOf(filter.getValue()))
: cb.like(path, wildCard + filter.getValue() + wildCard));
}q.where(filterCondition);
//Pagination
TypedQuery<T> s = entityManager.createQuery(q);
if (pageSize >= 0){
s.setMaxResults(pageSize);
}
if (first >= 0){
s.setFirstResult(first);
}
log.info("\n\n\n");
log.info("XXXXXXXXXxX");
log.info("=> CommonRepository - Total number of rows returned: ");
log.info("XXXXXXXXXXX");
log.info("\n\n\n");
return s.getResultList();
}
public <T extends Object> int count(Class<T> type, Map<String, String> filters){
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<T> root=cq.from(type);
// Filtering
Predicate filterCondition = cb.conjunction();
String wildCard = "%";
for (Map.Entry<String, String> filter : filters.entrySet()) {
String[] filterField = filter.getKey().split("\\.", 2);
Path path = filterField.length == 1 ? root.get(filterField[0]): root.join(filterField[0]).get(filterField[1]);
filterCondition = cb.and(filterCondition, filter.getValue().matches("[0-9]+")
? cb.equal(path, Long.valueOf(filter.getValue()))
: cb.like(path, wildCard + filter.getValue() + wildCard));
}cq.where(filterCondition);
cq.select(cb.count(root));
return entityManager.createQuery(cq).getSingleResult().intValue();
}
i am trying to mock an arraylist as follows using Powermock
MockDao Class
PowerMockito.mockStatic(DailyReceiptsAndExceptionsDetailsDao.class);
PowerMockito.mockStatic(UtilityFunctions.class);
DailyReceiptsAndExceptionsExport dailyExceptionsExport = Mockito.mock(DailyReceiptsAndExceptionsExport.class);
List<DailyReceiptsAndExceptionsDetailsGridDto> resultList = getDailyExceptions(inputDto);
try{
PowerMockito.whenNew(DailyReceiptsAndExceptionsExport.class).withArguments(Mockito.any(DailyReceiptsAndExceptionsDetailsInputDto.class)).thenReturn(dailyExceptionsExport);
Mockito.when(DailyReceiptsAndExceptionsDetailsDao.getDailyReceiptsAndExceptions(Mockito.any(DailyReceiptsAndExceptionsDetailsInputDto.class))).thenReturn(resultList);
Mockito.when(UtilityFunctions.processReportSchedule(scheduleId, jobId,dailyExceptionsExport,(List<DailyReceiptsAndExceptionResultDTO>)Mockito.any(), null, null)).thenReturn(true);
}catch(Exception e){
}
I need to write tests for the following class.
public static Response getOutboundAvgCubeAndWeightUtilization(
#QueryParam("dc") String dc,
#QueryParam("asn") String asn,
#QueryParam("sortBy") String sort,
#QueryParam("isExport") boolean isExport,
#QueryParam("fileType") String fileType,
#QueryParam("scheduleId") BigDecimal scheduleId,
#QueryParam("jobId") BigDecimal jobId) {
ResponseDTO responseDto = new ResponseDTO();
DailyReceiptsAndExceptionsDetailsInputDto inputDto = new DailyReceiptsAndExceptionsDetailsInputDto ();
inputDto.setAsn(asn);
inputDto.setDc(dc);
inputDto.setSortBy(sort);
inputDto.setFileType(fileType);
inputDto.setExport(isExport);
String filePath = "";
try {
DailyReceiptsAndExceptionResultDTO resultDto = DailyReceiptsAndExceptionsDetailsBusinessManager.getInstance().manageDailyReceiptsAndExceptionsDetails(inputDto);
List<DailyReceiptsAndExceptionResultDTO> resultsList = new ArrayList<DailyReceiptsAndExceptionResultDTO>();
resultsList.add(resultDto);
if(scheduleId != null) {
boolean responseStatus = UtilityFunctions.processReportSchedule(scheduleId, jobId, new DailyReceiptsAndExceptionsExport(inputDto), resultsList, null,null);
responseDto.setResult(Boolean.toString(responseStatus));
return CommonUtil.convertResponseToJson(responseDto);
}
}
My tests class is as follows.
#Test
public void testGetOutboundAvgCubeAndWeightUtilization_4()
throws Exception {
String dc = "5854";
String asn = "*";
String sort = "SKU";
boolean isExport = false;
String fileType = "";
BigDecimal scheduleId = new BigDecimal(100);
BigDecimal jobId = new BigDecimal(100);
DailyReceiptsAndExceptionsDetailsInputDto inputDto = new DailyReceiptsAndExceptionsDetailsInputDto ();
inputDto.setAsn(asn);
inputDto.setDc(dc);
inputDto.setSortBy(sort);
inputDto.setFileType(fileType);
inputDto.setExport(isExport);
DailyReceiptsAndExceptionsDetailsMockDAO.mockgetDailyExceptions(inputDto, scheduleId, jobId);
Response result = DailyReceiptsAndExceptionsDetailsService.getOutboundAvgCubeAndWeightUtilization(dc, asn, sort, isExport, fileType, scheduleId, jobId);
String output = result.getEntity().toString();
assertEquals(true,output.contains("\"result\": \"true\""));
}
when iam running the test case, it was throwing error because, i think the mocking of the list is not correct.
Can anybody tell how to run this test scenario ....
Your mocks appear to be fine.
JUnit is failing the test because the line
assertEquals(true,output.contains("\"result\": \"true\""));
is failing: this means that your String output does not contain the text "result": "true"
Perhaps one way for you to figure out what is wrong is to either print out the value of output prior to the assertEquals() call or use a debugger to see what the value of output is.
As a side note, assertEquals(true, <condition>) is very verbose, you can use assertTrue(<condition>) instead.
According to your comment the test is simply failing. (AssertionErrors are JUnit's way of saying that your test failed.)
You could get a better error message if you use Hamcrest. Therefore you have to change the last two lines of your code:
assertThat(result.getEntity(), hasToString(containsString("\"result\": \"true\"")));
Add some static imports for org.hamcrest.MatcherAssert.assertThat and org.hamcrest.Matchers.*.
The new error message may help you finding the error.
I am trying to create a REST service using Nancy FX in a C# environment. I can easily do a Response.AsJson and it all looks good. But I want the response to omit any properties that are null.
I have not been able to figure out how to do this yet.
Could someone point to me towards a help document or a blog post somewhere, that explains how to do this.
Thanks,
JP
I would create a dynamic anonymous type and return that. So let's say you have a User object like this:
public class User
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
You want to pass back an instance of this type as a JSON response so you will have some code like this:
Get["/user/{userid}"] = parameters =>
{
var user = UserService.GetById(Db, (string)parameters.userid);
if (user == null) return HttpStatusCode.UnprocessableEntity;
return Response.AsJson(user);
};
But you don't want to return the User instance, instead you want to return an separate instance of a dynamic type that will only implement a property if the property value is not null for a given instance.
So I would suggest code something like this:
Get["/user/{userid}"] = parameters =>
{
var user = UserService.GetById(Db, (string)parameters.userid);
if (user == null) return HttpStatusCode.UnprocessableEntity;
dynamic userDTO = new ExpandoObject();
userDTO.Id = user.Id;
if (!string.IsNullOrEmpty(user.FirstName)) userDTO.FirstName = user.FirstName;
if (!string.IsNullOrEmpty(user.LastName)) userDTO.Lastname = user.LastName;
return Response.AsJson((ExpandoObject)userDTO);
};
Note 1
You don't need to test for the Id since that is implied by the successful return of the User instance from the database.
Note 2
You need to use a dynamic type so you can include ad hoc properties. The problem is that extension methods cannot accept dynamic types. To avoid this you need to declare it as an ExpandoObject but use it as a dynamic. This trick incurs a processing overhead but it allows you to cast the dynamic to an ExpandoObject when passing it in to the AsJson() extension method.
I have multiple queries that I'd like to union together, then compile the entire thing. The uncompiled query runs fine, but an "InvalidOperationException: Member access 'Int32 Id' of 'UserQuery+Foo' not legal on type 'System.Linq.IQueryable`1[UserQuery+Foo]." exception is thrown when the same query is compiled and run.
How do I fix this?
void Main()
{
var db = new MyDataContext( "..." );
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from ab in GetA(dc).Union( GetB(dc) )
group ab by new { ab.Id, ab.Name } into grp
select new Foo
{
Id = grp.Key.Id,
Name = grp.Key.Name,
Total = grp.Count()
};
var final = CompiledQuery.Compile ( queryExpression );
var result1 = queryExpression.Compile () (db, 0); // calling the original query works fine
var result2 = final (db, 0); // calling the compiled query throws an exception
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public int Total { get; set; }
}
IQueryable<Foo> GetA( DataContext db )
{
return from b in db.GetTable<Bar>()
where b.IsActive
select new Foo { Id = b.Id, Name = b.Name };
}
IQueryable<Foo> GetB( DataContext db )
{
return from b in db.GetTable<Bar>()
where !b.IsActive
select new Foo { Id = b.Id, Name = b.Name };
}
EDIT
It looks like the union and grouping are irrelevant. Removing those elements from the query still causes an exception when compiled:
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from a in GetA(dc)
select new Foo
{
Id = a.Id,
Name = a.Name,
Total = 42
};
Replacing the call to GetA(dc) with dc.GetTable<Bar>() and adding the where clause fixes the issue.
So, is connecting separate queries together like this simply not possible for compiled queries?
EDIT #2
James' answer hit the nail on the head. Simplifying the query even further reveals the root problem:
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from a in GetA(dc)
select a;
This query throws NotSupportedException: Method 'System.Linq.IQueryable``1[UserQuery+Foo] GetA(System.Data.Linq.DataContext)' has no supported translation to SQL.
Pulling the call to GetA out into a separate variable assignment, then using that variable in the query throws a InvalidOperationException: Sequence contains more than one element exception.
I had the same issue and what seemed to do the trick for me was separating out an inline static method call that returned IQueryable<> so that I stored this deferred query into a variable and referenced that.
I think this is a bug in Linq to SQL but at least there is a reasonable workaround.
My guess is that the linq compiler doesn't understand the methods returning IQueryable.
To compile it, those methods would probably have to return some form of Expression<>.
I am using LINQ and am having a hard time understanding how I can make new "domain model" classes work within LINQ while querying across tables. I am using Linq to SQL, and C# in .NET 3.5.
Suppose I want an Extended Client class:
public class ExtendedClient
{
public int ID { get; set; }
public string Name { get; set; }
public string strVal { get; set; }
}
and in my data layer, I want to populate this from two tables (dc is my DataContext):
public ExtendedClient getExtendedClient(int clientID)
{
var c = dc.GetTable<tClient>();
var cs = dc.GetTable<tClientSetting>();
var q = from client in c
join setting in cs
on client.ClientID equals setting.ClientID
where client.ClientID == clientID
select new ExtendedClient { client, setting.strValue };
return q;
}
I am trying to return the row in the table tClient plus one extra column in tClientSetting.
The annoying errors I get are :
Cannot initialize type 'ExtendedClient' with a collection initializer because it does not implement 'System.Collections.IEnumerable'
and
Cannot implicitly convert type 'System.Linq.IQueryable' to 'ExtendedClient'. An explicit conversion exists (are you missing a cast?)
I realize this is a basic error, but I cannot determine how BEST to implement the IEnumerable because I cannot find an example.
Do I have to do this every time I want a specialized object? Thanks in advance.
public ExtendedClient getExtendedClient(int clientID)
{
var c = dc.GetTable<tClient>();
var cs = dc.GetTable<tClientSetting>();
var q = from client in c
join setting in cs
on client.ClientID equals setting.ClientID
where client.ClientID == clientID
select new ExtendedClient { ID = client.ClientID, Name = client.Name, strVal = setting.strValue };
return q.Single();
}
You'll have to do a similar thing every time you need to return a specialized object. If you don't need to return it, you don't have to specify the type and you won't need a special class. You could use anonymous types:
from client in c
join setting in cs
on client.ClientID equals setting.ClientID
where client.ClientID == clientID
select new { ID = client.ClientID, Name = client.Name, strVal = setting.strValue };
Why do you use a special type for this?
I think you can do client.Settings.strValue if you setup the Client-Settings relationship to create a property Client.Settings (instead of Settings.Client). And as far as I remember such configuration is possible in LINQ.