Add nullable attribute to SqlParameter in object - sqlparameter

I am using an object for parameters when calling ExecuteSqlRawAsync in Asp.Net Core 3.1 Web Api. I know that SqlParameter() has several overloads, one of which is IsNullable, but I cannot figure out how to use it. I am currently setting values to DBNull using a loop:
object[] parameters =
{
new SqlParameter("#EmployeeId", employee.Id),
new SqlParameter("#FirstName", employee.FirstName),
new SqlParameter("#MiddleName", employee.MiddleName),
new SqlParameter("#LastName", employee.LastName),
new SqlParameter("#SuffixId", employee.SuffixId),
new SqlParameter("#NickName", employee.NickName),
new SqlParameter("#UseNickName", employee.UseNickName),
new SqlParameter("#UpdatebyId",employee.UpdateById)
};
foreach(SqlParameter parameter in parameters)
{
if(parameter.Value == null)
{
parameter.Value = DBNull.Value;
}
}
await context.Database.ExecuteSqlRawAsync("exec stp_API_Update_Employee {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}", parameters);
but it seems it could/would be more efficient if I could add it like:
SqlParameter("#SuffixId", employee.SuffixId, true)
Is it possible to do it this way, or is the foreach loop my only option?

Related

Convert Linq query to List without using generic parameter

If I have an unevaluated query:
var q = (my linq query);
That happens to return a type of DbSet<T> and I need it to resolve to a List<T> because I'm about to lose the context within which it was created.
Normally I would just say q.Cast<T>.ToList() but at this place in the code I don't have T so how do I do this?
I do have the System.Type of T however. I came up with a work around but I am having to load a new List<T> (created with reflection) with the results of q. I don't like it because it's awkward and I'm loading another list but maybe loading a list is what ToList() does anyway.
Is there a better way?
public static System.Collections.IEnumerable RootCollection(string collectionPropertyName)
{
using (var db = new Model1())
{
var col = GetRootCollection(db, collectionPropertyName);
System.Type generic = typeof(List<>);
System.Type constructed = generic.MakeGenericType(col.GetType().GetGenericArguments().First());
var list = constructed.GetConstructor(new Type[] {col.GetType() }).Invoke(new object[] { col });
return (System.Collections.IEnumerable)list;
}
}

MVC6 Web Api - Return Plain Text

I have looked at other similar questions (such as this one Is there a way to force ASP.NET Web API to return plain text?) on SO but they all seem to address WebAPI 1 or 2, not the latest version you use with MVC6.
I need to return plain text on one of my Web API controllers. Only one - the others should keep returning JSON. This controller is used for dev purposes to output a list of records in a database, which will be imported into a traffic load generator. This tool takes CSV as input so I'm trying to output that (users will only have to save the content of the page).
[HttpGet]
public HttpResponseMessage AllProductsCsv()
{
IList<Product> products = productService.GetAllProducts();
var sb = new StringBuilder();
sb.Append("Id,PartNumber");
foreach(var product in products)
{
sb.AppendFormat("{0},{1}", product.Id, product.PartNumber);
}
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StringContent(sb.ToString(), System.Text.Encoding.UTF8, "text/plain");
return result;
}
Based on various searches this seems like the simplest way to proceed since I'll need this only for this one action. However when I request this, I get the following output:
{
   "Version": {
      "Major": 1,
      "Minor": 1,
      "Build": -1,
      "Revision": -1,
      "MajorRevision": -1,
      "MinorRevision": -1
   },
   "Content": {
      "Headers": [
         {
            "Key": "Content-Type",
            "Value": [
               "text/plain; charset=utf-8"
            ]
         }
      ]
   },
   "StatusCode": 200,
   "ReasonPhrase": "OK",
   "Headers": [],
   "RequestMessage": null,
   "IsSuccessStatusCode": true
}
So it seems that MVC still tries to output JSON, and I have no idea why they'd output these values. When I debug the code step by step I can see that the content of the StringBuilder is okay and what I want to output.
Is there any easy way to just output a string with MVC6?
Have a go with this:
var httpResponseMessage = new HttpResponseMessage();
httpResponseMessage.Content = new StringContent(stringBuilder.ToString());
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
return httpResponseMessage;
The solution was to return a FileContentResult. This seems to bypass the built-in formatters:
[HttpGet]
public FileContentResult AllProductsCsv()
{
IList<Product> products = productService.GetAllProducts();
var sb = new StringBuilder();
sb.Append("Id,PartNumber\n");
foreach(var product in products)
{
sb.AppendFormat("{0},{1}\n", product.Id, product.PartNumber);
}
return File(Encoding.UTF8.GetBytes(sb.ToString()), "text/csv");
}

Unable to insert dynamic object to Elastic Search using NEST

I am creating a dynamic object. I assign the values via IDictionary. Add the collections of the IDictionary to the object. Then I add the dynamic object to Elastic Search using NEST code. It throws me stackoverflow exception."An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll"
Here is what I have tried.
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node,defaultIndex: "test-index");
var client = new ElasticClient(settings);
try
{
dynamic x = new ExpandoObject();
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("NewProp", "test1");
dic.Add("NewProp3", "test1");
x = dic;
var index3 = client.Index(x);
}
catch (Exception ex)
{
string j = ex.StackTrace;
}
I need to create an index in ElasticSearch, using a dynamic object, because I will be having an excel work book consisting of over 300 worksheet, and each and every sheet will be named as type, and the contents inside the worksheet will be the _source.
In the above example 'x' the dynamic object created is the name of the worksheet, and the values added into the dictionary are the rows and columns of excel sheet.
Where am I going wrong.
Regards,
Hema
I belive you can skip ExpandoObject and just index Dictionary<string, object>().
var dictionary = new Dictionary<string, object>();
dictionary.Add("NewProp", "test1");
dictionary.Add("NewProp3", "test1");
client.Index(dictionary);

The best way to modify a WebAPI OData QueryOptions.Filter

I am using the OData sample project at http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations. In the Get I want to be able to change the Filter in the QueryOptions of the EntitySetController:
public class ProductsController : EntitySetController<Product, int>
{
ProductsContext _context = new ProductsContext();
[Queryable(AllowedQueryOptions=AllowedQueryOptions.All)]
public override IQueryable<Product> Get()
{
var products = QueryOptions.ApplyTo(_context.Products).Cast<Product>();
return products.AsQueryable();
}
I would like to be able to find properties that are specifically referred to. I can do this by parsing this.QueryOptions.Filter.RawValue for the property names but I cannot update the RawValue as it is read only. I can however create another instance of FilterQueryOption from the modified RawValue but I cannot assign it to this.QueryOptions.Filter as this is read only too.
I guess I could call the new filter's ApplyTo passing it _context.Products, but then I will need to separately call the ApplyTo of the other properties of QueryOptions like Skip and OrderBy. Is there a better solution than this?
Update
I tried the following:
public override IQueryable<Product> Get()
{
IQueryable<Product> encryptedProducts = _context.Products;
var filter = QueryOptions.Filter;
if (filter != null && filter.RawValue.Contains("Name"))
{
var settings = new ODataQuerySettings();
var originalFilter = filter.RawValue;
var newFilter = ParseAndEncyptValue(originalFilter);
filter = new FilterQueryOption(newFilter, QueryOptions.Context);
encryptedProducts = filter.ApplyTo(encryptedProducts, settings).Cast<Product>();
if (QueryOptions.OrderBy != null)
{
QueryOptions.OrderBy.ApplyTo<Product>(encryptedProducts);
}
}
else
{
encryptedProducts = QueryOptions.ApplyTo(encryptedProducts).Cast<Product>();
}
var unencryptedProducts = encryptedProducts.Decrypt().ToList();
return unencryptedProducts.AsQueryable();
}
and it seems to be working up to a point. If I set a breakpoint I can see my products in the unencryptedProducts list, but when the method returns I don't get any items. I tried putting the [Queryable(AllowedQueryOptions=AllowedQueryOptions.All)] back on again but it had no effect. Any ideas why I am not getting an items?
Update 2
I discovered that my query was being applied twice even though I am not using the Queryable attribute. This meant that even though I had items to return the List was being queried with the unencrypted value and therefore no values were being returned.
I tried using an ODataController instead:
public class ODriversController : ODataController
{
//[Authorize()]
//[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<Products> Get(ODataQueryOptions options)
{
and this worked! Does this indicate that there is a bug in EntitySetController?
You would probably need to regenerate ODataQueryOptions to solve your issue. Let's say if you want to modify to add $orderby, you can do this like:
string url = HttpContext.Current.Request.Url.AbsoluteUri;
url += "&$orderby=name";
var request = new HttpRequestMessage(HttpMethod.Get, url);
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Product>("Product");
var options = new ODataQueryOptions<Product>(new ODataQueryContext(modelBuilder.GetEdmModel(), typeof(Product)), request);

Subsonic Single WHERE clause

Is it possible to apply a WHERE clause on a SubSonic query?
For example, I get get a single based on id...
db.Single<Storage>(id);
But how can I get a single based on a simple WHERE clause?
db.Single<Storage>(WHERE columnname == "value");
that's possible:
// Will return a Storage instance with property IsNew = true, if record does not exist
// since an object created with new never can be null
var storage1 = new Storage(1); // id = 1
var storage1 = new Storage(Storag.Columns.ColumnName, "value");
// Will return 0 if record not found (subsonic3 only)
var storage3 = (from s in Storage
where s.ColumnName == "value"
select s).SingleOrDefault();
// Will throw an exception if record not found (subsonic3 only)
var storage3 = (from s in Storage
where s.ColumnName == "value"
select s).Single();
Since db is a partial class you can extend it. Just create a new File within the same namespace (but another folder in your solution). This applies to subsonic 2 but will be similar to subsonic 3, I think.
public static partial class DB
{
public static T Single<T>(String columName, Object columnValue) where T: RecordBase<T>, new()
{
return Select().From<T>()
.Where(columnName).IsEqualTo(columnValue)
.ExecuteSingle<T>();
}
}
Thanks for the above, this was a help and eventually I simplified this to the below...
db.Single<Storage>(s => s.ColumnName == "value");

Resources