fluent nhibernate SQL Server 2008 R2 Express very long string saving issue - sql-server

I am trying to create my first NHibernate project, so it is possible I am doing something stupid here but have been Googling for a couple of days and not had any joy yet.
I have an Article object which has various properties:
public class Article {
public virtual string Title { get; set; }
public virtual string Body { get; set; }
}
I am using the fluent configuration to load the mappings:
configuration.Mappings(m => m.AutoMappings.Add((AutoMap.AssemblyOf<Article>())
.Conventions.Add(DefaultCascade.All())
.UseOverridesFromAssemblyOf<SchemaConfigurationController>())
The override is:
public class ArticleOverrideMapping : IAutoMappingOverride<Article>
{
public void Override(AutoMapping<Article> mapping)
{
//mapping.Map(x => x.Body).CustomSqlType("NVARCHAR(4000)");
//mapping.Map(article => article.Body).Length(10000);
//mapping.Map(article => article.Body).Length(Int32.MaxValue);
//mapping.Map(article => article.Body).CustomSqlType("NVARCHAR(max)");
//mapping.Map(article => article.Body).CustomSqlType("NVARCHAR(max)").Length(Int32.MaxValue);
mapping.Map(article => article.Body).CustomType("StringClob").CustomSqlType("NVARCHAR(max)");
}
}
I have tried each of the commented out lines (roughly in order of when I found a possible solution online). I can get SQL Server to create the nvarchar(max) column and if I use SQL management studio I can paste a LOT (185,602 words was largest test) into the Body column. My issue is trying to get it to save from the MVC site using NHibernate.
There are two main errors I get:
String or binary data would be truncated. The statement has been terminated.
This would occur if I didn't set the ".Length(Int32.MaxValue)" override.
The second Error that occurs (when the length is set):
The length of the string value exceeds the length configured in the mapping/parameter.
I am pretty confused as to what I should be doing at this point. My goal is to be able to store a very large string (an whole article) in SQL Server (and SQLite for testing, nvarchar(max) wasn't liked by SQLite) and get that back out, (and edit it) in an MVC site.
UPDATE
As per #Cymen's link I tried
.CustomSqlType("nvarchar(max)").Length(Int32.MaxValue).Nullable();
but this lead to the error:
The length of the string value exceeds the length configured in the mapping/parameter.
when I only tried to save 1201 words (all the word "test"). When I added the length on the end of the above mapping ".Length(Int32.MaxValue)" I still the same error.
update
wanted to confirm which versions I am using:
FluentNHibernate.1.3.0.733
NHibernate.3.3.1.4000
Microsoft.AspNet.Mvc.4.0.20710.0
final update
Kieren had it correct, I had completely forgotten that I took that property and ran markdownsharp on it on the server and populated a second property on the server. So it was the second property that I hadn't mapped that was actually blowing up, sorry.

this is how i normally handle it.
mapping.Map(x => x.Problem).CustomType("varchar(MAX)");
not sure what CustomSqlType is, but i've never used it, and this works.

Ok, folks. Same stuff, so i've did some tests.
It seems that int.MaxValue cannot be used as LENGTH for fluent. If you do that, the resulting create SQL will be nvarchar(255). So if nhibernate (fluent) still generates such a script, then he is awaiting 255 chars at max.
If you hovewer use int.MaxValue / 2, then everything is ok. At least in the script.
Only reasonable explanation: unicode string, so for a single char fluent automatically takes 2 bytes. SO internally fluent hibernate may do a multiplication by 2. And if we get above 2GB space, who knows what fluent will do...
Please let me know if it works with data too.

Related

EF Core 3.1.9 - FromRawSql using stored procedures stopped working - 'The underlying reader doesn't have as many fields as expected.'

At one point using FromSqlRaw to call stored procedures worked for me. I did not change anything in the project but now calling any stored procedure using FromSqlRaw returns
The underlying reader doesn't have as many fields as expected
I removed the model from the project and performed a BUILD. Then added the model back with no luck. I reduced the model and stored procedure to return a single column, no luck.
I tried adding Microsoft.EntityFrameworkCore.Relational as a dependency, no luck. All my unit test that use FromSqlRaw to call a stored procedure return the same error and at one time they all worked.
I have received Windows updates but nothing I know about that would have affected EF Core. I have run through all internet problem solving I can find. I am starting to think I will need to use ADO as a work around but I do not want a work around when it worked for me at one point. Something changed on my machine but I am not sure what to cause this problem.
Here is my test method in case my code is messed up. It is very straight forward not much to mess up. I tried the "var" out of desperation.
[TestMethod]
public void WorkOrderBOMGridABS()
{
List<WorkOrderBOMGridABS> baseList = new List<WorkOrderBOMGridABS>();
using (WorkOrderDataContext context = new WorkOrderDataContext())
{
var param = new SqlParameter[] {
new SqlParameter() {
ParameterName = "#WorkOrderId",
SqlDbType = System.Data.SqlDbType.Int,
Direction = System.Data.ParameterDirection.Input,
Value = 38385
}
};
baseList = context.WorkOrderBOMGridABS.FromSqlRaw("[dbo].[WorkOrderBOMGridABS] #WorkOrderId", param).ToList();
//var results = context.WorkOrderBOMGridABS.FromSqlRaw("[dbo].[WorkOrderBOMGridABS] #WorkOrderId", param).ToList();
Assert.IsNotNull(baseList);
}
}
I was using an old table to get the Unit Of Measure value that had an integer ID value. I switched it to use a new table with a VARCHAR ID value. Making this change to the stored proc and model code allowed the FromRawSql to work. Not sure why because while the integer ID value was getting an integer, either 0 or number other than 0, it was a valid value for the model. Any error message I received did not mention this UnitId field. It was a pain but I am glad it is resolved. At least until the next error I run into that much is guaranteed.

SQL Server 2012 assembly execution failure - System.NullReferenceException: Object reference not set to an instance of an object

I am trying to execute a UDF which uses a CLR assembly. Each time I try to run it I get the below error:
Msg 6522, Level 16, State 1, Line 45
A .NET Framework error occurred during execution of user-defined routine or aggregate "Geocode":
System.NullReferenceException: Object reference not set to an instance of an object.
at ProSpatial.UserDefinedFunctions.GeocodeUDF(SqlString countryRegion, SqlString adminDistrict, SqlString locality, SqlString postalCode, SqlString addressLine)
It is a geocoding assembly, which is based on the below blog:
https://alastaira.wordpress.com/2012/05/04/geocoding-in-sql-server-with-the-bing-maps-locations-api/
Is there anything I can do to fix it? It was working fine, but just stopped working recently. I changed the Bing Maps key to a new one, but that hasn't resolved the issue. Anyone have any ideas?
Cheers
Edit: I entered a formatted URL into Chrome, to see if I can get the error. I entered the below URL format:
http://dev.virtualearth.net/REST/v1/Locations?countryRegion={0}&adminDistrict={1}&locality={2}&postalCode={3}&addressLine={4}&key={5}&output=xml
All I did was to replace items 0 to 5 with their respective entries. I left the curly brackets in there, and then also tried it without the curly brackets. Without the curly brackets, the URL returned a result with no issues.
In the browser, I am getting geocoded results, but not in SQL any more
Just worked it out. One of the address fields that was being geocoded was null in the database, and the API did not like that. So I removed that from the geocoding list
Looking at the code in that blog, if you are passing in a NULL, then it's not the API that's throwing the error. The error is happening because NULL values are not being handled when the method is first called. The code just casts the SqlString input parameters to string without first checking to see if there is a value in the SqlString variable. SqlString is very similar to a nullable string.
Fortunately, it is rather easy to adjust the code to properly handle NULL values in the input parameters. Starting with a redacted snippet of the original code below, I will show how to do this for one parameter and you can repeat that modification for the others (well, the ones that might actually be NULL in the DB; no need to do this for parameters that are guaranteed to be there due to being in a NOT NULL column).
public static SqlGeography GeocodeUDF(
SqlString countryRegion,
SqlString adminDistrict,
SqlString locality,
SqlString postalCode,
SqlString addressLine
)
{
...
string localAdminDistrict = string.Empty;
if (!adminDistrict.IsNull)
{
localAdminDistrict = adminDistrict.Value;
}
// Attempt to geocode the requested address
try
{
geocodeResponse = Geocode(
(string)countryRegion,
localAdminDistrict,
(string)locality,
(string)postalCode,
(string)addressLine
);
}
All I did was:
Added a local variable for localAdminDistrict, defaulted to an empty string.
Added an if block to set localAdminDistrict if adminDistrict is not null.
Updated the call to Geocode() to use localAdminDistrict instead of (string)adminDistrict.
This should work as long as the Bing Maps API is ok with an empty value for adminDistrict (i.e. ...&adminDistrict=&locality=... ), as opposed to adminDistrict not being present in the GET request (which is easy enough, it just requires an additional modification).
ALSO: As long as you are going to be in there updating the code, you really should move the calls to the Close() and Dispose() methods into a finally block for that try / catch.
For more info on working with SQLCLR in general, please visit: SQLCLR Info

How to best store and manipulate large datasets locally in a flutter app

i´m currently building a Flutter app that includes a larger set of data (like 2000-10000 pieces of text).
I´m relatively new to Flutter delevopment so i have no idea what databases are the best for this case.
The app needs no connection to the internet a all data is on the device after downloading.
You only need to query this data extensively and build now datasets out of it.
I researched a bit, but the most common used database (hive) seems not to be suitable for my needs.
If anyone could help, I´d appreciate it.
It seems ObjectBox is best For Large Data ,it Performs very Well
[Check this package best suits for your data][1]
import 'package:objectbox/objectbox.dart';
class Note {
// Each "Entity" needs a unique integer ID property.
// Add `#Id()` annotation if its name isn't "id" (case insensitive).
int id = 0;
String? text;
DateTime date;
#Transient() // Make this field ignored, not stored in the database.
int? notPersisted;
// An empty default constructor is needed but you can use optional args.
Note({this.text, DateTime? date}) : date = date ?? DateTime.now();
// Note: just for logs in the examples below(), not needed by ObjectBox.
toString() => 'Note{id: $id, text: $text}';
}```

Trouble using dbforge with PyroCMS (CI based CMS)

I have been using PyroCMS and CI for quite some time, and truly love it.
I am extending a DB module that will allow an admin user to manage a DB without having to use something like phpMyAdmin.
The only thing I have been able to get working however is Browsing a table's field values (i.e 'SELECT * FROM 'table_name').
I want to include more functions, but I can't seem to get dbforge to work properly. I know it is loaded because dbforge is used to uninstall modules. I also get no error when calling functions from it.
Here is an example of my code from the controller (dbforge has already been loaded).
public function drop($table_name)
{
$table_name = $this->uri->segment(4);
$this->dbforge->drop_table($table_name);
redirect('admin/database/tables');
}
Lets say the function gets called from this url:
.../admin/database/drop/table_name
It appears to work... but instead it just redirects to the tables overview.
Is there something I am missing? Shouldn't [$this->dbforge->drop_table($table_name);] always drop a table (given $table_name is valid)?
EDIT
As a work around, I was able to use:
public function drop($table_name)
{
$table_name = $this->uri->segment(4);
//$this->dbforge->drop_table($table_name);
$this->db->query("DROP TABLE ".$table_name);
redirect('admin/database/tables');
return TRUE;
}
I really would like to use DB forge, however...
I think you might be getting a little confused by the site prefixes in PyroCMS 1.3.x.
By default all installations of Community and Professional will have default_ as a prefix for all tables in the first site. If you have Professional you can add new sites and the site reference will be whatever_ instead of default_
This prefix is accounted for by dbforge, so when you want to delete default_blog you would just delete:
/admin/database/drop/blog
Also, why are you accepting the $table_name as an argument then overriding it with a uri segment?
Also, why are you accepting the $table_name as an argument then overriding it with a uri segment?
See what I did there? xD
public function drop($table_name)
{
$this->dbforge->drop_table($table_name);
redirect('admin/database/tables');
}

Using Linq to filter parents by their children

Having some problems with my Silverlight app (with RIA services) filtering my results. The idea is on the client I set up the EntityQuery and its filters and call load. However this isn't working for me.
Heres my code.
public void FireQuery(string filterValue)
{
EntityQuery<Parent> query = m_ParentDomainContext.GetParentQuery();
query = query.Where(p => p.Children.Any(c => c.Name.Contains(filterValue)));
m_ParentDomainContext.Load(query, Query_Completed, null);
}
Compiles just fine, however, runtime I get "Query operator 'Any' is not supported." Exception.
Does anyone know of a good way to filter like this? Again, I'm looking for a way to set this up on the client.
EDIT: I should note, I've tried a few other queries as well, with similar results:
query = query.Where(p => p.Children.Where(c => c.Name.Contains(filterValue)).Count() != 0);
query = query.Where(p => p.Children.Where(c => c.Name.Contains(filterValue)).FirstOrDefault != null);
query = query.Where(p => p.Children.Where(c => c.Name.Contains(filterValue)).Any());
Query Operator 'Count/FirstOrDefault/Any' is not supported. I'm clearly missing something here...
As I tried to play around a little with this, I figured out that methods like First, Any and Count can't be used with LINQ to Entities (and, I believe, even NHibernate) over WCF RIA Services because they're not defined on the IQueryable itself, but, instread, are extention methods defined in the System.Linqnamespace. That is precisely why this shows as a run-time exception and not a compile-time error. The only extension methods that can be used here are those found in System.ServiceModel.DomainServices.Client (such as Where, Skip, Take, OrderBy, etc.).
This has to do with the "EntityQuery" objects, because those need to be composed and sent back to the server, whereas for the collections (such as m_ParentDomainContext.Parents in your case), you can use the System.Linq extension methods freely.
In order to implement this functionality, I suggest, as Thomas Levesque said, to expose it from the server in order to only get the data you want, or, alternatively, you can compose a query using the available constructs (the ones in System.ServiceModel.DomainServices.Client) and then apply the other filters on the resulting data (where you can use extension methods from the System.Linq namespace).
PS: I tried this with both classic Entity Framework and Entity Framework CodeFirst, and had the same results.
I hope this helps

Resources