Sitecore 8 Sitecore.Eventing.Remote.PublishEndRemoteEvent - mongodb

I am using Sitecore 8 and after I stopped the MongoDB service and set the setting in configs to stop using MongoDB for analytics this specific error:
ERROR Exception while handling event Sitecore.Eventing.Remote.PublishEndRemoteEvent
Exception: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Source: Sitecore.SharedSource.PartialLanguageFallback
at Sitecore.SharedSource.PartialLanguageFallback.Providers.FallbackLanguageProvider.ClearFallbackCaches(ItemUri itemUri, Database database)
at Sitecore.SharedSource.PartialLanguageFallback.Providers.FallbackLanguageProvider.<>c__DisplayClass1.<InitializeEventHandlers>b__0(PublishEndRemoteEvent event)
at Sitecore.Eventing.EventProvider.RaiseEvent(Object event, Type eventType, EventContext context)
To disable the Analytics database I've used the indications from here.
Does PublishEndRemoteEvent use somehow MongoDB? Do you know how can I fix this so I won't get it anymore?

You need to generate a new assembly for Sitecore.SharedSource.PartialLanguageFallback with the following change:
Update the below file as follows:
Sitecore.SharedSource.PartialLanguageFallback/Providers/FallbackLanguageProvider.cs
private void ClearFallbackCaches(ItemUri itemUri, Database database) {
var cache = _fallbackValuesCaches[database.Name];
var ignore_cache = _fallbackIgnoreCaches[database.Name];
if (cache != null)
{
// Added a null check on itemUri
if (itemUri == null)
cache.Clear();
else
cache.RemoveKeysContaining(itemUri.ItemID.ToString());
}
if (ignore_cache != null)
{
// Added a null check on itemUri
if (itemUri == null)
ignore_cache.Clear();
else
ignore_cache.RemoveKeysContaining(itemUri.ItemID.ToString());
} }
https://blog.horizontalintegration.com/2014/05/03/sitecore-partial-language-fallback-cache-clearing-issue/

Related

Cannot attach database file when using Entity Framework Core Migration commands

I am using EntityFramework Core commands to migration database. The command I am using is like the docs suggests: dnx . ef migration apply. The problem is when specifying AttachDbFileName in connection string, the following error appear: Unable to Attach database file as database xxxxxxx. This is the connection string I am using:
Data Source=(LocalDB)\mssqllocaldb;Integrated Security=True;Initial Catalog=EfGetStarted2;AttachDbFileName=D:\EfGetStarted2.mdf
Please help how to attach the db file to another location.
Thanks
EF core seem to have troubles with AttachDbFileName or doesn't handle it at all.
EnsureDeleted changes the database name to master but keeps any AttachDbFileName value, which leads to an error since we cannot attach the master database to another file.
EnsureCreated opens a connection using the provided AttachDbFileName value, which leads to an error since the file of the database we want to create does not yet exist.
EF6 has some logic to handle these use cases, see SqlProviderServices.DbCreateDatabase, so everything worked quite fine.
As a workaround I wrote some hacky code to handle these scenarios:
public static void EnsureDatabase(this DbContext context, bool reset = false)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (reset)
{
try
{
context.Database.EnsureDeleted();
}
catch (SqlException ex) when (ex.Number == 1801)
{
// HACK: EF doesn't interpret error 1801 as already existing database
ExecuteStatement(context, BuildDropStatement);
}
catch (SqlException ex) when (ex.Number == 1832)
{
// nothing to do here (see below)
}
}
try
{
context.Database.EnsureCreated();
}
catch (SqlException ex) when (ex.Number == 1832)
{
// HACK: EF doesn't interpret error 1832 as non existing database
ExecuteStatement(context, BuildCreateStatement);
// this takes some time (?)
WaitDatabaseCreated(context);
// re-ensure create for tables and stuff
context.Database.EnsureCreated();
}
}
private static void WaitDatabaseCreated(DbContext context)
{
var timeout = DateTime.UtcNow + TimeSpan.FromMinutes(1);
while (true)
{
try
{
context.Database.OpenConnection();
context.Database.CloseConnection();
}
catch (SqlException)
{
if (DateTime.UtcNow > timeout)
throw;
continue;
}
break;
}
}
private static void ExecuteStatement(DbContext context, Func<SqlConnectionStringBuilder, string> statement)
{
var builder = new SqlConnectionStringBuilder(context.Database.GetDbConnection().ConnectionString);
using (var connection = new SqlConnection($"Data Source={builder.DataSource}"))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = statement(builder);
command.ExecuteNonQuery();
}
}
}
private static string BuildDropStatement(SqlConnectionStringBuilder builder)
{
var database = builder.InitialCatalog;
return $"drop database [{database}]";
}
private static string BuildCreateStatement(SqlConnectionStringBuilder builder)
{
var database = builder.InitialCatalog;
var datafile = builder.AttachDBFilename;
var dataname = Path.GetFileNameWithoutExtension(datafile);
var logfile = Path.ChangeExtension(datafile, ".ldf");
var logname = dataname + "_log";
return $"create database [{database}] on primary (name = '{dataname}', filename = '{datafile}') log on (name = '{logname}', filename = '{logfile}')";
}
It's far from nice, but I'm using it for integration testing anyway. For "real world" scenarios using EF migrations should be the way to go, but maybe the root cause of this issue is the same...
Update
The next version will include support for AttachDBFilename.
There may be a different *.mdf file already attached to a database named EfGetStarted2... Try dropping/detaching that database then try again.
You might also be running into problems if the user LocalDB is running as doesn't have correct permissions to the path.

Entityframework Concurrency

I have the following Scenario:
I have 2 web api functions, which delete / insert data into a SQL Server database. The data Access is handled via .net entityframework v6. The insert / delete methods were only called from a local running c# program. I am using HttpClient class to call the web api methods. The web methods works as follows, when I call insert all existing records will be deleted and the new ones will be inserted, so there is no real update process.
Here are my 2 functions:
[HttpDelete()]
public async Task<int> DeleteStartlist(int eventid, int run, int heat, string category)
{
_data.dbsStartlistEntries.RemoveRange(_data.dbsStartlistEntries.Where(s => s.Event.Id == eventid && s.RoundOrder == run && s.HeatOrder == heat && s.Category == category));
return await _data.SaveChangesAsync();
}
[HttpPost()]
public async Task<int> UpdateStartlists(int eventid, List<StartlistEntry> en)
{
try
{
if (en.Count == 0)
return 0;
var xdel = await DeleteStartlist(eventid, en[0].RoundOrder, en[0].HeatOrder, en[0].Category);
var ev = await _data.dbsEvents.FindAsync(eventid);
if (ev != null)
{
en.ForEach(e => e.Event = ev);
_data.dbsStartlistEntries.AddRange(en);
}
return await _data.SaveChangesAsync();
}
catch (System.Exception ex)
{
return 1;
}
}
But now I have the following Problem. For example when I call the Update Method 10 times in a row without waiting between the function calls I receive following exception:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
For me this sounds like a concurrency Problem, but I do not really know how to solve it.
So here is my question, is there a way to let the api calls wait for each other server side, or are they always running concurrent or is there a way to lock the database?

Entity Framework 6 Primary Key configuration issue on save of Entities

I'm trying to save few entities with this code:
this.UserService.Users.Add(eUser);
if (SelectedRewindItems != null && SelectedRewindItems.Count > 0)
{
foreach (var ug in SelectedRewindItems)
{
HpmModel.Usergroup nUg = new HpmModel.Usergroup();
decimal numId;
var a = Decimal.TryParse(ug.Key.ToString(), out numId);
nUg.Groupid = numId;
nUg.Userid = eUser.Userid;
// eUser.Usergroups.Add(nUg);
this.UserService.Usergroups.Add(nUg);
}
}
var submitOp = this.UserService.SubmitChanges();
IsSuccess = true;
ActionMessageOnButtonSuccess = User.Fname + " " + User.Lname + " Added Successfully !!";
string message = null;
if (submitOp.EntitiesInError.Any())
{
message = string.Empty;
Entity entityInError = submitOp.EntitiesInError.First();
if (entityInError.EntityConflict != null)
{
EntityConflict conflict = entityInError.EntityConflict;
foreach (var cm in conflict.PropertyNames)
{
message += string.Format("{0}", cm);
}
}
else if (entityInError.ValidationErrors.Any())
{
message += "\r\n" + entityInError.ValidationErrors.First().ErrorMessage;
}
MessageBox.Show(message);
}
else
{
MessageBox.Show("Submit Done");
}
But I'm getting this error:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state.
Inner exception message: Saving or accepting changes failed because more than one entity of type 'HpmModel.Usergroup' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass2a.b__27()
at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges()
at OpenRiaServices.DomainServices.EntityFramework.LinqToEntitiesDomainService1.InvokeSaveChanges(Boolean retryOnConflict) in c:\Code\Repos\openriaservices\OpenRiaServices.DomainServices.EntityFramework\Framework\LinqToEntitiesDomainService.cs:line 145
at OpenRiaServices.DomainServices.EntityFramework.LinqToEntitiesDomainService`1.PersistChangeSet() in c:\Code\Repos\openriaservices\OpenRiaServices.DomainServices.EntityFramework\Framework\LinqToEntitiesDomainService.cs:line 138
at OpenRiaServices.DomainServices.Server.DomainService.PersistChangeSetInternal()
at OpenRiaServices.DomainServices.Server.DomainService.Submit(ChangeSet changeSet)
InnerException: System.InvalidOperationException
HResult=-2146233079
Message=Saving or accepting changes failed because more than one entity of type 'HpmModel.Usergroup' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
Source=EntityFramework
StackTrace:
at System.Data.Entity.Core.Objects.ObjectStateManager.FixupKey(EntityEntry entry)
at System.Data.Entity.Core.Objects.EntityEntry.AcceptChanges()
at System.Data.Entity.Core.Objects.ObjectContext.AcceptAllChanges()
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
InnerException:
When I checked the Database Entities got saved but still it is giving me this issues.
Is this because I'm trying save them after saving User & Then UserGroup entities separatly. or Child Entities should get saved with Parent Entities. I'm a beginner so facing challanges.
After wasting a lot of time, I came to know that I need to fix my EDMX file & Entity Code.
So I added in my entity:
[DatabaseGenerated( DatabaseGeneratedOption.Identity)]
In the SSDL file in my Users -> Usersgroup (1-M) Relationship
Usersgroup Id Node I Added:
StoreGeneratedPattern="Identity" [SSDL]
In CSDL:
ed:StoreGeneratedPattern="Identity"
In my code:
this.UserService.Users.Add(eUser);
if (SelectedRewindItems != null && SelectedRewindItems.Count > 0)
{
foreach (var ug in SelectedRewindItems)
{
HpmModel.Usergroup nUg = new HpmModel.Usergroup();
decimal numId;
var a = Decimal.TryParse(ug.Key.ToString(), out numId);
nUg.Groupid = numId;
nUg.Userid = eUser.Userid;
eUser.Usergroups.Add(nUg);
}
}
After applying these changes, SaveChanges() worked.
This blog post helped me.

EF: EnsureLoadedForContext method

I am reading EF's source code and found this method below. According to the method name, it make sure that the dbcontext is loaded. When I test this with EF Codefirst sample, this method is added the current assembly (my sample console) to "_knownAssemblies"..
I don't see any code of loading the assembly. And I don't see any code that checks whether the assembly is loaded or not.
Is that the naming issue or Did I miss out something? Thanks in advance.
public virtual void EnsureLoadedForContext(Type contextType)
{
DebugCheck.NotNull(contextType);
Debug.Assert(typeof(DbContext).IsAssignableFrom(contextType));
var contextAssembly = contextType.Assembly;
if (contextType == typeof(DbContext)
|| _knownAssemblies.ContainsKey(contextAssembly))
{
return;
}
if (_configurationOverrides.IsValueCreated)
{
lock (_lock)
{
if (_configurationOverrides.Value.Count != 0)
{
return;
}
}
}
if (!ConfigurationSet)
{
var foundConfigurationType =
_loader.TryLoadFromConfig(AppConfig.DefaultInstance) ??
_finder.TryFindConfigurationType(contextType);
if (foundConfigurationType != null)
{
SetConfigurationType(foundConfigurationType);
}
}
else if (!contextAssembly.IsDynamic // Don't throw for proxy contexts created in dynamic assemblies
&& !_loader.AppConfigContainsDbConfigurationType(AppConfig.DefaultInstance))
{
var foundType = _finder.TryFindConfigurationType(contextType);
if (foundType != null)
{
if (_configuration.Value.Owner.GetType() == typeof(DbConfiguration))
{
throw new InvalidOperationException(Strings.ConfigurationNotDiscovered(foundType.Name));
}
if (foundType != _configuration.Value.Owner.GetType())
{
throw new InvalidOperationException(
Strings.SetConfigurationNotDiscovered(_configuration.Value.Owner.GetType().Name, contextType.Name));
}
}
}
_knownAssemblies.TryAdd(contextAssembly, null);
}
The method EnsureLoadedForContext does not load the context but loads a configuration for the context type passed to the method. When you look at the name of the method with the type name on which the method is created (DbConfigurationManager.EnsureLoadedForContext) it is much more clear that the method is related to loading a configuration rather than loading a context. Finally you can look at a comment to one of the bugs which reads:
EnsureLoadedForContext is called from various places as soon as a context type is known to ensure that the correct DbConfiguration is found.

delete and then insert object Entity framework

I have this method that delete object if exist and insert the new instance any way :
internal void SaveCarAccident(WcfContracts.BLObjects.Contract.Dtos.CarAccident DTOCarAccident)
{
using(var context = BLObjectsFactory.Create())
{
context.ContextOptions.ProxyCreationEnabled = false;
CarAccident NewCarAccident = ConvertToCarAccident(DTOCarAccident);
CarAccident carFromDB = context.CarAccident.FirstOrDefault(current => current.CarAccidentKey.Equals(NewCarAccident.CarAccidentKey));
if(carFromDB != null)
context.CarAccident.DeleteObject(carFromDB);
context.CarAccident.AddObject(NewCarAccident);
context.SaveChanges();
}
}
I sometimes get exception that the key already exist in table.
I wnted to know if the way I save the changes is a problem (saving after delete and insert and not after each one)
At the time I got the exception there were few clients that activate the method at the same time I blocked other clients from writing already, but is this may be the problem ?
Thanks
Eran